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 # turns an org list into an org tree
1040 sub build_org_tree {
1042 my( $self, $orglist) = @_;
1044 return $orglist unless ref $orglist;
1045 return $$orglist[0] if @$orglist == 1;
1048 $a->ou_type <=> $b->ou_type ||
1049 $a->name cmp $b->name } @$orglist;
1051 for my $org (@list) {
1053 next unless ($org and defined($org->parent_ou));
1054 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1055 next unless $parent;
1057 $parent->children([]) unless defined($parent->children);
1058 push( @{$parent->children}, $org );
1066 __PACKAGE__->register_method(
1067 method => "get_org_descendants",
1068 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1071 # depth is optional. org_unit is the id
1072 sub get_org_descendants {
1073 my( $self, $client, $org_unit, $depth ) = @_;
1074 my $orglist = $apputils->simple_scalar_request(
1076 "open-ils.storage.actor.org_unit.descendants.atomic",
1077 $org_unit, $depth );
1078 return $self->build_org_tree($orglist);
1082 __PACKAGE__->register_method(
1083 method => "get_org_ancestors",
1084 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1087 # depth is optional. org_unit is the id
1088 sub get_org_ancestors {
1089 my( $self, $client, $org_unit, $depth ) = @_;
1090 my $orglist = $apputils->simple_scalar_request(
1092 "open-ils.storage.actor.org_unit.ancestors.atomic",
1093 $org_unit, $depth );
1094 return $self->build_org_tree($orglist);
1098 __PACKAGE__->register_method(
1099 method => "get_standings",
1100 api_name => "open-ils.actor.standings.retrieve"
1105 return $user_standings if $user_standings;
1106 return $user_standings =
1107 $apputils->simple_scalar_request(
1109 "open-ils.cstore.direct.config.standing.search.atomic",
1110 { id => { "!=" => undef } }
1116 __PACKAGE__->register_method(
1117 method => "get_my_org_path",
1118 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1121 sub get_my_org_path {
1122 my( $self, $client, $auth, $org_id ) = @_;
1123 my $e = new_editor(authtoken=>$auth);
1124 return $e->event unless $e->checkauth;
1125 $org_id = $e->requestor->ws_ou unless defined $org_id;
1127 return $apputils->simple_scalar_request(
1129 "open-ils.storage.actor.org_unit.full_path.atomic",
1134 __PACKAGE__->register_method(
1135 method => "patron_adv_search",
1136 api_name => "open-ils.actor.patron.search.advanced" );
1137 sub patron_adv_search {
1138 my( $self, $client, $auth, $search_hash,
1139 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1141 my $e = new_editor(authtoken=>$auth);
1142 return $e->event unless $e->checkauth;
1143 return $e->event unless $e->allowed('VIEW_USER');
1144 return $U->storagereq(
1145 "open-ils.storage.actor.user.crazy_search", $search_hash,
1146 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1150 __PACKAGE__->register_method(
1151 method => "update_passwd",
1153 api_name => "open-ils.actor.user.password.update");
1155 __PACKAGE__->register_method(
1156 method => "update_passwd",
1157 api_name => "open-ils.actor.user.username.update");
1159 __PACKAGE__->register_method(
1160 method => "update_passwd",
1161 api_name => "open-ils.actor.user.email.update");
1164 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1165 my $e = new_editor(xact=>1, authtoken=>$auth);
1166 return $e->die_event unless $e->checkauth;
1168 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1169 or return $e->die_event;
1170 my $api = $self->api_name;
1172 if( $api =~ /password/o ) {
1174 # make sure the original password matches the in-database password
1175 return OpenILS::Event->new('INCORRECT_PASSWORD')
1176 if md5_hex($orig_pw) ne $db_user->passwd;
1177 $db_user->passwd($new_val);
1181 # if we don't clear the password, the user will be updated with
1182 # a hashed version of the hashed version of their password
1183 $db_user->clear_passwd;
1185 if( $api =~ /username/o ) {
1187 # make sure no one else has this username
1188 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1189 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1190 $db_user->usrname($new_val);
1192 } elsif( $api =~ /email/o ) {
1193 $db_user->email($new_val);
1197 $e->update_actor_user($db_user) or return $e->die_event;
1205 __PACKAGE__->register_method(
1206 method => "check_user_perms",
1207 api_name => "open-ils.actor.user.perm.check",
1208 notes => <<" NOTES");
1209 Takes a login session, user id, an org id, and an array of perm type strings. For each
1210 perm type, if the user does *not* have the given permission it is added
1211 to a list which is returned from the method. If all permissions
1212 are allowed, an empty list is returned
1213 if the logged in user does not match 'user_id', then the logged in user must
1214 have VIEW_PERMISSION priveleges.
1217 sub check_user_perms {
1218 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1220 my( $staff, $evt ) = $apputils->checkses($login_session);
1221 return $evt if $evt;
1223 if($staff->id ne $user_id) {
1224 if( $evt = $apputils->check_perms(
1225 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1231 for my $perm (@$perm_types) {
1232 if($apputils->check_perms($user_id, $org_id, $perm)) {
1233 push @not_allowed, $perm;
1237 return \@not_allowed
1240 __PACKAGE__->register_method(
1241 method => "check_user_perms2",
1242 api_name => "open-ils.actor.user.perm.check.multi_org",
1244 Checks the permissions on a list of perms and orgs for a user
1245 @param authtoken The login session key
1246 @param user_id The id of the user to check
1247 @param orgs The array of org ids
1248 @param perms The array of permission names
1249 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1250 if the logged in user does not match 'user_id', then the logged in user must
1251 have VIEW_PERMISSION priveleges.
1254 sub check_user_perms2 {
1255 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1257 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1258 $authtoken, $user_id, 'VIEW_PERMISSION' );
1259 return $evt if $evt;
1262 for my $org (@$orgs) {
1263 for my $perm (@$perms) {
1264 if($apputils->check_perms($user_id, $org, $perm)) {
1265 push @not_allowed, [ $org, $perm ];
1270 return \@not_allowed
1274 __PACKAGE__->register_method(
1275 method => 'check_user_perms3',
1276 api_name => 'open-ils.actor.user.perm.highest_org',
1278 Returns the highest org unit id at which a user has a given permission
1279 If the requestor does not match the target user, the requestor must have
1280 'VIEW_PERMISSION' rights at the home org unit of the target user
1281 @param authtoken The login session key
1282 @param userid The id of the user in question
1283 @param perm The permission to check
1284 @return The org unit highest in the org tree within which the user has
1285 the requested permission
1288 sub check_user_perms3 {
1289 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1291 my( $staff, $target, $org, $evt );
1293 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1294 $authtoken, $userid, 'VIEW_PERMISSION' );
1295 return $evt if $evt;
1297 my $tree = $self->get_org_tree();
1298 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1302 sub _find_highest_perm_org {
1303 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1304 my $org = $apputils->find_org($org_tree, $start_org );
1308 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1310 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1317 __PACKAGE__->register_method(
1318 method => 'check_user_work_perms',
1319 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1323 Returns a set of org units which represent the highest orgs in
1324 the org tree where the user has the requested permission. The
1325 purpose of this method is to return the smallest set of org units
1326 which represent the full expanse of the user's ability to perform
1327 the requested action. The user whose perms this method should
1328 check is implied by the authtoken. /,
1330 {desc => 'authtoken', type => 'string'},
1331 {desc => 'permission name', type => 'string'}
1333 return => {desc => 'An array of org IDs'}
1337 sub check_user_work_perms {
1338 my($self, $conn, $auth, $perm) = @_;
1339 my $e = new_editor(authtoken=>$auth);
1340 return $e->event unless $e->checkauth;
1341 return $U->find_highest_work_orgs($e, $perm);
1344 __PACKAGE__->register_method(
1345 method => 'check_user_perms4',
1346 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1348 Returns the highest org unit id at which a user has a given permission
1349 If the requestor does not match the target user, the requestor must have
1350 'VIEW_PERMISSION' rights at the home org unit of the target user
1351 @param authtoken The login session key
1352 @param userid The id of the user in question
1353 @param perms An array of perm names to check
1354 @return An array of orgId's representing the org unit
1355 highest in the org tree within which the user has the requested permission
1356 The arrah of orgId's has matches the order of the perms array
1359 sub check_user_perms4 {
1360 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1362 my( $staff, $target, $org, $evt );
1364 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1365 $authtoken, $userid, 'VIEW_PERMISSION' );
1366 return $evt if $evt;
1369 return [] unless ref($perms);
1370 my $tree = $self->get_org_tree();
1372 for my $p (@$perms) {
1373 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1381 __PACKAGE__->register_method(
1382 method => "user_fines_summary",
1383 api_name => "open-ils.actor.user.fines.summary",
1384 notes => <<" NOTES");
1385 Returns a short summary of the users total open fines, excluding voided fines
1386 Params are login_session, user_id
1387 Returns a 'mous' object.
1390 sub user_fines_summary {
1391 my( $self, $client, $auth, $user_id ) = @_;
1392 my $e = new_editor(authtoken=>$auth);
1393 return $e->event unless $e->checkauth;
1394 my $user = $e->retrieve_actor_user($user_id)
1395 or return $e->event;
1397 if( $user_id ne $e->requestor->id ) {
1398 return $e->event unless
1399 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1402 # run this inside a transaction to prevent replication delay errors
1403 my $ses = $U->start_db_session();
1404 my $s = $ses->request(
1405 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1406 $U->rollback_db_session($ses);
1413 __PACKAGE__->register_method(
1414 method => "user_transactions",
1415 api_name => "open-ils.actor.user.transactions",
1416 notes => <<" NOTES");
1417 Returns a list of open user transactions (mbts objects);
1418 Params are login_session, user_id
1419 Optional third parameter is the transactions type. defaults to all
1422 __PACKAGE__->register_method(
1423 method => "user_transactions",
1424 api_name => "open-ils.actor.user.transactions.have_charge",
1425 notes => <<" NOTES");
1426 Returns a list of all open user transactions (mbts objects) that have an initial charge
1427 Params are login_session, user_id
1428 Optional third parameter is the transactions type. defaults to all
1431 __PACKAGE__->register_method(
1432 method => "user_transactions",
1433 api_name => "open-ils.actor.user.transactions.have_balance",
1434 notes => <<" NOTES");
1435 Returns a list of all open user transactions (mbts objects) that have a balance
1436 Params are login_session, user_id
1437 Optional third parameter is the transactions type. defaults to all
1440 __PACKAGE__->register_method(
1441 method => "user_transactions",
1442 api_name => "open-ils.actor.user.transactions.fleshed",
1443 notes => <<" NOTES");
1444 Returns an object/hash of transaction, circ, title where transaction = an open
1445 user transactions (mbts objects), circ is the attached circluation, and title
1446 is the title the circ points to
1447 Params are login_session, user_id
1448 Optional third parameter is the transactions type. defaults to all
1451 __PACKAGE__->register_method(
1452 method => "user_transactions",
1453 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1454 notes => <<" NOTES");
1455 Returns an object/hash of transaction, circ, title where transaction = an open
1456 user transactions that has an initial charge (mbts objects), circ is the
1457 attached circluation, and title is the title the circ points to
1458 Params are login_session, user_id
1459 Optional third parameter is the transactions type. defaults to all
1462 __PACKAGE__->register_method(
1463 method => "user_transactions",
1464 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1465 notes => <<" NOTES");
1466 Returns an object/hash of transaction, circ, title where transaction = an open
1467 user transaction that has a balance (mbts objects), circ is the attached
1468 circluation, and title is the title the circ points to
1469 Params are login_session, user_id
1470 Optional third parameter is the transaction type. defaults to all
1473 __PACKAGE__->register_method(
1474 method => "user_transactions",
1475 api_name => "open-ils.actor.user.transactions.count",
1476 notes => <<" NOTES");
1477 Returns an object/hash of transaction, circ, title where transaction = an open
1478 user transactions (mbts objects), circ is the attached circluation, and title
1479 is the title the circ points to
1480 Params are login_session, user_id
1481 Optional third parameter is the transactions type. defaults to all
1484 __PACKAGE__->register_method(
1485 method => "user_transactions",
1486 api_name => "open-ils.actor.user.transactions.have_charge.count",
1487 notes => <<" NOTES");
1488 Returns an object/hash of transaction, circ, title where transaction = an open
1489 user transactions that has an initial charge (mbts objects), circ is the
1490 attached circluation, and title is the title the circ points to
1491 Params are login_session, user_id
1492 Optional third parameter is the transactions type. defaults to all
1495 __PACKAGE__->register_method(
1496 method => "user_transactions",
1497 api_name => "open-ils.actor.user.transactions.have_balance.count",
1498 notes => <<" NOTES");
1499 Returns an object/hash of transaction, circ, title where transaction = an open
1500 user transaction that has a balance (mbts objects), circ is the attached
1501 circluation, and title is the title the circ points to
1502 Params are login_session, user_id
1503 Optional third parameter is the transaction type. defaults to all
1506 __PACKAGE__->register_method(
1507 method => "user_transactions",
1508 api_name => "open-ils.actor.user.transactions.have_balance.total",
1509 notes => <<" NOTES");
1510 Returns an object/hash of transaction, circ, title where transaction = an open
1511 user transaction that has a balance (mbts objects), circ is the attached
1512 circluation, and title is the title the circ points to
1513 Params are login_session, user_id
1514 Optional third parameter is the transaction type. defaults to all
1519 sub user_transactions {
1520 my( $self, $client, $login_session, $user_id, $type ) = @_;
1522 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1523 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1524 return $evt if $evt;
1526 my $api = $self->api_name();
1530 if(defined($type)) { @xact = (xact_type => $type);
1532 } else { @xact = (); }
1535 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1536 ->run($login_session => $user_id => $type);
1538 if($api =~ /have_charge/o) {
1540 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1542 } elsif($api =~ /have_balance/o) {
1544 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1547 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1551 if($api =~ /total/o) {
1553 for my $t (@$trans) {
1554 $total += $t->balance_owed;
1557 $logger->debug("Total balance owed by user $user_id: $total");
1561 if($api =~ /count/o) { return scalar @$trans; }
1562 if($api !~ /fleshed/o) { return $trans; }
1565 for my $t (@$trans) {
1567 if( $t->xact_type ne 'circulation' ) {
1568 push @resp, {transaction => $t};
1572 my $circ = $apputils->simple_scalar_request(
1574 "open-ils.cstore.direct.action.circulation.retrieve",
1579 my $title = $apputils->simple_scalar_request(
1581 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1582 $circ->target_copy );
1586 my $u = OpenILS::Utils::ModsParser->new();
1587 $u->start_mods_batch($title->marc());
1588 my $mods = $u->finish_mods_batch();
1589 $mods->doc_id($title->id) if $mods;
1591 push @resp, {transaction => $t, circ => $circ, record => $mods };
1599 __PACKAGE__->register_method(
1600 method => "user_transaction_retrieve",
1601 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1603 notes => <<" NOTES");
1604 Returns a fleshedtransaction record
1606 __PACKAGE__->register_method(
1607 method => "user_transaction_retrieve",
1608 api_name => "open-ils.actor.user.transaction.retrieve",
1610 notes => <<" NOTES");
1611 Returns a transaction record
1613 sub user_transaction_retrieve {
1614 my( $self, $client, $login_session, $bill_id ) = @_;
1616 # XXX I think I'm deprecated... make sure
1618 my $trans = $apputils->simple_scalar_request(
1620 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1624 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1625 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1626 return $evt if $evt;
1628 my $api = $self->api_name();
1629 if($api !~ /fleshed/o) { return $trans; }
1631 if( $trans->xact_type ne 'circulation' ) {
1632 $logger->debug("Returning non-circ transaction");
1633 return {transaction => $trans};
1636 my $circ = $apputils->simple_scalar_request(
1638 "open-ils..direct.action.circulation.retrieve",
1641 return {transaction => $trans} unless $circ;
1642 $logger->debug("Found the circ transaction");
1644 my $title = $apputils->simple_scalar_request(
1646 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1647 $circ->target_copy );
1649 return {transaction => $trans, circ => $circ } unless $title;
1650 $logger->debug("Found the circ title");
1654 my $u = OpenILS::Utils::ModsParser->new();
1655 $u->start_mods_batch($title->marc());
1656 $mods = $u->finish_mods_batch();
1658 if ($title->id == OILS_PRECAT_RECORD) {
1659 my $copy = $apputils->simple_scalar_request(
1661 "open-ils.cstore.direct.asset.copy.retrieve",
1662 $circ->target_copy );
1664 $mods = new Fieldmapper::metabib::virtual_record;
1665 $mods->doc_id(OILS_PRECAT_RECORD);
1666 $mods->title($copy->dummy_title);
1667 $mods->author($copy->dummy_author);
1671 $logger->debug("MODSized the circ title");
1673 return {transaction => $trans, circ => $circ, record => $mods };
1677 __PACKAGE__->register_method(
1678 method => "hold_request_count",
1679 api_name => "open-ils.actor.user.hold_requests.count",
1681 notes => <<" NOTES");
1682 Returns hold ready/total counts
1684 sub hold_request_count {
1685 my( $self, $client, $login_session, $userid ) = @_;
1687 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1688 $login_session, $userid, 'VIEW_HOLD' );
1689 return $evt if $evt;
1692 my $holds = $apputils->simple_scalar_request(
1694 "open-ils.cstore.direct.action.hold_request.search.atomic",
1697 fulfillment_time => {"=" => undef },
1698 cancel_time => undef,
1703 for my $h (@$holds) {
1704 next unless $h->capture_time and $h->current_copy;
1706 my $copy = $apputils->simple_scalar_request(
1708 "open-ils.cstore.direct.asset.copy.retrieve",
1712 if ($copy and $copy->status == 8) {
1717 return { total => scalar(@$holds), ready => scalar(@ready) };
1721 __PACKAGE__->register_method(
1722 method => "checkedout_count",
1723 api_name => "open-ils.actor.user.checked_out.count__",
1725 notes => <<" NOTES");
1726 Returns a transaction record
1730 sub checkedout_count {
1731 my( $self, $client, $login_session, $userid ) = @_;
1733 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1734 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1735 return $evt if $evt;
1737 my $circs = $apputils->simple_scalar_request(
1739 "open-ils.cstore.direct.action.circulation.search.atomic",
1740 { usr => $userid, stop_fines => undef }
1741 #{ usr => $userid, checkin_time => {"=" => undef } }
1744 my $parser = DateTime::Format::ISO8601->new;
1747 for my $c (@$circs) {
1748 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1749 my $due = $due_dt->epoch;
1751 if ($due < DateTime->today->epoch) {
1756 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1760 __PACKAGE__->register_method(
1761 method => "checked_out",
1762 api_name => "open-ils.actor.user.checked_out",
1765 Returns a structure of circulations objects sorted by
1766 out, overdue, lost, claims_returned, long_overdue.
1767 A list of IDs are returned of each type.
1768 lost, long_overdue, and claims_returned circ will not
1769 be "finished" (there is an outstanding balance or some
1770 other pending action on the circ).
1772 The .count method also includes a 'total' field which
1773 sums all "open" circs
1777 __PACKAGE__->register_method(
1778 method => "checked_out",
1779 api_name => "open-ils.actor.user.checked_out.count",
1781 signature => q/@see open-ils.actor.user.checked_out/
1785 my( $self, $conn, $auth, $userid ) = @_;
1787 my $e = new_editor(authtoken=>$auth);
1788 return $e->event unless $e->checkauth;
1790 if( $userid ne $e->requestor->id ) {
1791 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1794 my $count = $self->api_name =~ /count/;
1795 return _checked_out( $count, $e, $userid );
1799 my( $iscount, $e, $userid ) = @_;
1802 my $meth = 'open-ils.storage.actor.user.checked_out';
1803 $meth = "$meth.count" if $iscount;
1804 return $U->storagereq($meth, $userid);
1806 # XXX Old code - moved to storage
1807 #------------------------------------------------------------------------------
1808 #------------------------------------------------------------------------------
1809 my $circs = $e->search_action_circulation(
1810 { usr => $userid, checkin_time => undef });
1812 my $parser = DateTime::Format::ISO8601->new;
1814 # split the circs up into overdue and not-overdue circs
1816 for my $c (@$circs) {
1817 if( $c->due_date ) {
1818 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1819 my $due = $due_dt->epoch;
1820 if ($due < DateTime->today->epoch) {
1830 my( @open, @od, @lost, @cr, @lo );
1832 while (my $c = shift(@out)) {
1833 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1834 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1835 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1836 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1839 while (my $c = shift(@overdue)) {
1840 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1841 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1842 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1843 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1848 total => @open + @od + @lost + @cr + @lo,
1849 out => scalar(@open),
1850 overdue => scalar(@od),
1851 lost => scalar(@lost),
1852 claims_returned => scalar(@cr),
1853 long_overdue => scalar(@lo)
1861 claims_returned => \@cr,
1862 long_overdue => \@lo
1867 sub _checked_out_WHAT {
1868 my( $iscount, $e, $userid ) = @_;
1870 my $circs = $e->search_action_circulation(
1871 { usr => $userid, stop_fines => undef });
1873 my $mcircs = $e->search_action_circulation(
1876 checkin_time => undef,
1877 xact_finish => undef,
1881 push( @$circs, @$mcircs );
1883 my $parser = DateTime::Format::ISO8601->new;
1885 # split the circs up into overdue and not-overdue circs
1887 for my $c (@$circs) {
1888 if( $c->due_date ) {
1889 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1890 my $due = $due_dt->epoch;
1891 if ($due < DateTime->today->epoch) {
1892 push @overdue, $c->id;
1901 # grab all of the lost, claims-returned, and longoverdue circs
1902 #my $open = $e->search_action_circulation(
1903 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1906 # these items have stop_fines, but no xact_finish, so money
1907 # is owed on them and they have not been checked in
1908 my $open = $e->search_action_circulation(
1911 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1912 xact_finish => undef,
1913 checkin_time => undef,
1918 my( @lost, @cr, @lo );
1919 for my $c (@$open) {
1920 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1921 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1922 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1928 total => @$circs + @lost + @cr + @lo,
1929 out => scalar(@out),
1930 overdue => scalar(@overdue),
1931 lost => scalar(@lost),
1932 claims_returned => scalar(@cr),
1933 long_overdue => scalar(@lo)
1939 overdue => \@overdue,
1941 claims_returned => \@cr,
1942 long_overdue => \@lo
1948 __PACKAGE__->register_method(
1949 method => "checked_in_with_fines",
1950 api_name => "open-ils.actor.user.checked_in_with_fines",
1952 signature => q/@see open-ils.actor.user.checked_out/
1954 sub checked_in_with_fines {
1955 my( $self, $conn, $auth, $userid ) = @_;
1957 my $e = new_editor(authtoken=>$auth);
1958 return $e->event unless $e->checkauth;
1960 if( $userid ne $e->requestor->id ) {
1961 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1964 # money is owed on these items and they are checked in
1965 my $open = $e->search_action_circulation(
1968 xact_finish => undef,
1969 checkin_time => { "!=" => undef },
1974 my( @lost, @cr, @lo );
1975 for my $c (@$open) {
1976 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1977 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1978 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1983 claims_returned => \@cr,
1984 long_overdue => \@lo
1996 __PACKAGE__->register_method(
1997 method => "user_transaction_history",
1998 api_name => "open-ils.actor.user.transactions.history",
2000 notes => <<" NOTES");
2001 Returns a list of billable transaction ids for a user, optionally by type
2003 __PACKAGE__->register_method(
2004 method => "user_transaction_history",
2005 api_name => "open-ils.actor.user.transactions.history.have_charge",
2007 notes => <<" NOTES");
2008 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2010 __PACKAGE__->register_method(
2011 method => "user_transaction_history",
2012 api_name => "open-ils.actor.user.transactions.history.have_balance",
2014 notes => <<" NOTES");
2015 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2017 __PACKAGE__->register_method(
2018 method => "user_transaction_history",
2019 api_name => "open-ils.actor.user.transactions.history.still_open",
2021 notes => <<" NOTES");
2022 Returns a list of billable transaction ids for a user that are not finished
2024 __PACKAGE__->register_method(
2025 method => "user_transaction_history",
2026 api_name => "open-ils.actor.user.transactions.history.have_bill",
2028 notes => <<" NOTES");
2029 Returns a list of billable transaction ids for a user that has billings
2035 sub _user_transaction_history {
2036 my( $self, $client, $login_session, $user_id, $type ) = @_;
2038 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2039 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2040 return $evt if $evt;
2042 my $api = $self->api_name();
2047 @xact = (xact_type => $type) if(defined($type));
2048 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2049 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2051 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2053 my $trans = $apputils->simple_scalar_request(
2055 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2056 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2058 return [ map { $_->id } @$trans ];
2062 =head SEE APPUTILS.PM
2067 for my $x (@xacts) {
2068 my $s = new Fieldmapper::money::billable_transaction_summary;
2071 $s->xact_start( $x->xact_start );
2072 $s->xact_finish( $x->xact_finish );
2076 for my $b (@{ $x->billings }) {
2077 next if ($U->is_true($b->voided));
2078 $to += ($b->amount * 100);
2079 $lb ||= $b->billing_ts;
2080 if ($b->billing_ts ge $lb) {
2081 $lb = $b->billing_ts;
2082 $s->last_billing_note($b->note);
2083 $s->last_billing_ts($b->billing_ts);
2084 $s->last_billing_type($b->billing_type);
2088 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2092 for my $p (@{ $x->payments }) {
2093 next if ($U->is_true($p->voided));
2094 $tp += ($p->amount * 100);
2095 $lp ||= $p->payment_ts;
2096 if ($p->payment_ts ge $lp) {
2097 $lp = $p->payment_ts;
2098 $s->last_payment_note($p->note);
2099 $s->last_payment_ts($p->payment_ts);
2100 $s->last_payment_type($p->payment_type);
2103 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2105 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2107 $s->xact_type( 'grocery' ) if ($x->grocery);
2108 $s->xact_type( 'circulation' ) if ($x->circulation);
2117 sub user_transaction_history {
2118 my( $self, $conn, $auth, $userid, $type ) = @_;
2120 # run inside of a transaction to prevent replication delays
2121 my $e = new_editor(xact=>1, authtoken=>$auth);
2122 return $e->die_event unless $e->checkauth;
2124 if( $e->requestor->id ne $userid ) {
2125 return $e->die_event
2126 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2129 my $api = $self->api_name;
2130 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2132 my @xacts = @{ $e->search_money_billable_transaction(
2133 [ { usr => $userid, @xact_finish },
2135 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2136 order_by => { mbt => 'xact_start DESC' },
2144 #my @mbts = _make_mbts( @xacts );
2145 my @mbts = $U->make_mbts( @xacts );
2147 if(defined($type)) {
2148 @mbts = grep { $_->xact_type eq $type } @mbts;
2151 if($api =~ /have_balance/o) {
2152 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2155 if($api =~ /have_charge/o) {
2156 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2159 if($api =~ /have_bill/o) {
2160 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2168 __PACKAGE__->register_method(
2169 method => "user_perms",
2170 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2172 notes => <<" NOTES");
2173 Returns a list of permissions
2176 my( $self, $client, $authtoken, $user ) = @_;
2178 my( $staff, $evt ) = $apputils->checkses($authtoken);
2179 return $evt if $evt;
2181 $user ||= $staff->id;
2183 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2187 return $apputils->simple_scalar_request(
2189 "open-ils.storage.permission.user_perms.atomic",
2193 __PACKAGE__->register_method(
2194 method => "retrieve_perms",
2195 api_name => "open-ils.actor.permissions.retrieve",
2196 notes => <<" NOTES");
2197 Returns a list of permissions
2199 sub retrieve_perms {
2200 my( $self, $client ) = @_;
2201 return $apputils->simple_scalar_request(
2203 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2204 { id => { '!=' => undef } }
2208 __PACKAGE__->register_method(
2209 method => "retrieve_groups",
2210 api_name => "open-ils.actor.groups.retrieve",
2211 notes => <<" NOTES");
2212 Returns a list of user groupss
2214 sub retrieve_groups {
2215 my( $self, $client ) = @_;
2216 return new_editor()->retrieve_all_permission_grp_tree();
2219 __PACKAGE__->register_method(
2220 method => "retrieve_org_address",
2221 api_name => "open-ils.actor.org_unit.address.retrieve",
2222 notes => <<' NOTES');
2223 Returns an org_unit address by ID
2224 @param An org_address ID
2226 sub retrieve_org_address {
2227 my( $self, $client, $id ) = @_;
2228 return $apputils->simple_scalar_request(
2230 "open-ils.cstore.direct.actor.org_address.retrieve",
2235 __PACKAGE__->register_method(
2236 method => "retrieve_groups_tree",
2237 api_name => "open-ils.actor.groups.tree.retrieve",
2238 notes => <<" NOTES");
2239 Returns a list of user groups
2241 sub retrieve_groups_tree {
2242 my( $self, $client ) = @_;
2243 return new_editor()->search_permission_grp_tree(
2248 flesh_fields => { pgt => ["children"] },
2249 order_by => { pgt => 'name'}
2256 # turns an org list into an org tree
2258 sub build_group_tree {
2260 my( $self, $grplist) = @_;
2262 return $grplist unless (
2263 ref($grplist) and @$grplist > 1 );
2265 my @list = sort { $a->name cmp $b->name } @$grplist;
2268 for my $grp (@list) {
2270 if ($grp and !defined($grp->parent)) {
2274 my ($parent) = grep { $_->id == $grp->parent} @list;
2276 $parent->children([]) unless defined($parent->children);
2277 push( @{$parent->children}, $grp );
2285 __PACKAGE__->register_method(
2286 method => "add_user_to_groups",
2287 api_name => "open-ils.actor.user.set_groups",
2288 notes => <<" NOTES");
2289 Adds a user to one or more permission groups
2292 sub add_user_to_groups {
2293 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2295 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2296 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2297 return $evt if $evt;
2299 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2300 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2301 return $evt if $evt;
2303 $apputils->simplereq(
2305 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2307 for my $group (@$groups) {
2308 my $link = Fieldmapper::permission::usr_grp_map->new;
2310 $link->usr($userid);
2312 my $id = $apputils->simplereq(
2314 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2320 __PACKAGE__->register_method(
2321 method => "get_user_perm_groups",
2322 api_name => "open-ils.actor.user.get_groups",
2323 notes => <<" NOTES");
2324 Retrieve a user's permission groups.
2328 sub get_user_perm_groups {
2329 my( $self, $client, $authtoken, $userid ) = @_;
2331 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2332 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2333 return $evt if $evt;
2335 return $apputils->simplereq(
2337 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2341 __PACKAGE__->register_method(
2342 method => "get_user_work_ous",
2343 api_name => "open-ils.actor.user.get_work_ous",
2344 notes => <<" NOTES");
2345 Retrieve a user's work org units.
2347 __PACKAGE__->register_method(
2348 method => "get_user_work_ous",
2349 api_name => "open-ils.actor.user.get_work_ous.ids",
2350 notes => <<" NOTES");
2351 Retrieve a user's work org units.
2355 sub get_user_work_ous {
2356 my( $self, $client, $auth, $userid ) = @_;
2357 my $e = new_editor(authtoken=>$auth);
2358 return $e->event unless $e->checkauth;
2359 $userid ||= $e->requestor->id;
2361 if($e->requestor->id != $userid) {
2362 my $user = $e->retrieve_actor_user($userid)
2363 or return $e->event;
2364 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2367 return $e->search_permission_usr_work_ou_map({usr => $userid})
2368 unless $self->api_name =~ /.ids$/;
2370 # client just wants a list of org IDs
2371 return $U->get_user_work_ou_ids($e, $userid);
2377 __PACKAGE__->register_method (
2378 method => 'register_workstation',
2379 api_name => 'open-ils.actor.workstation.register.override',
2380 signature => q/@see open-ils.actor.workstation.register/);
2382 __PACKAGE__->register_method (
2383 method => 'register_workstation',
2384 api_name => 'open-ils.actor.workstation.register',
2386 Registers a new workstion in the system
2387 @param authtoken The login session key
2388 @param name The name of the workstation id
2389 @param owner The org unit that owns this workstation
2390 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2391 if the name is already in use.
2394 sub register_workstation {
2395 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2397 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2398 return $e->die_event unless $e->checkauth;
2399 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2400 my $existing = $e->search_actor_workstation({name => $name})->[0];
2404 if( $self->api_name =~ /override/o ) {
2405 # workstation with the given name exists.
2407 if($owner ne $existing->owning_lib) {
2408 # if necessary, update the owning_lib of the workstation
2410 $logger->info("changing owning lib of workstation ".$existing->id.
2411 " from ".$existing->owning_lib." to $owner");
2412 return $e->die_event unless
2413 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2415 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2417 $existing->owning_lib($owner);
2418 return $e->die_event unless $e->update_actor_workstation($existing);
2424 "attempt to register an existing workstation. returning existing ID");
2427 return $existing->id;
2430 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2434 my $ws = Fieldmapper::actor::workstation->new;
2435 $ws->owning_lib($owner);
2437 $e->create_actor_workstation($ws) or return $e->die_event;
2439 return $ws->id; # note: editor sets the id on the new object for us
2442 __PACKAGE__->register_method (
2443 method => 'workstation_list',
2444 api_name => 'open-ils.actor.workstation.list',
2446 Returns a list of workstations registered at the given location
2447 @param authtoken The login session key
2448 @param ids A list of org_unit.id's for the workstation owners
2451 sub workstation_list {
2452 my( $self, $conn, $authtoken, @orgs ) = @_;
2454 my $e = new_editor(authtoken=>$authtoken);
2455 return $e->event unless $e->checkauth;
2460 unless $e->allowed('REGISTER_WORKSTATION', $o);
2461 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2472 __PACKAGE__->register_method (
2473 method => 'fetch_patron_note',
2474 api_name => 'open-ils.actor.note.retrieve.all',
2476 Returns a list of notes for a given user
2477 Requestor must have VIEW_USER permission if pub==false and
2478 @param authtoken The login session key
2479 @param args Hash of params including
2480 patronid : the patron's id
2481 pub : true if retrieving only public notes
2485 sub fetch_patron_note {
2486 my( $self, $conn, $authtoken, $args ) = @_;
2487 my $patronid = $$args{patronid};
2489 my($reqr, $evt) = $U->checkses($authtoken);
2490 return $evt if $evt;
2493 ($patron, $evt) = $U->fetch_user($patronid);
2494 return $evt if $evt;
2497 if( $patronid ne $reqr->id ) {
2498 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2499 return $evt if $evt;
2501 return $U->cstorereq(
2502 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2503 { usr => $patronid, pub => 't' } );
2506 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2507 return $evt if $evt;
2509 return $U->cstorereq(
2510 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2513 __PACKAGE__->register_method (
2514 method => 'create_user_note',
2515 api_name => 'open-ils.actor.note.create',
2517 Creates a new note for the given user
2518 @param authtoken The login session key
2519 @param note The note object
2522 sub create_user_note {
2523 my( $self, $conn, $authtoken, $note ) = @_;
2524 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2525 return $e->die_event unless $e->checkauth;
2527 my $user = $e->retrieve_actor_user($note->usr)
2528 or return $e->die_event;
2530 return $e->die_event unless
2531 $e->allowed('UPDATE_USER',$user->home_ou);
2533 $note->creator($e->requestor->id);
2534 $e->create_actor_usr_note($note) or return $e->die_event;
2540 __PACKAGE__->register_method (
2541 method => 'delete_user_note',
2542 api_name => 'open-ils.actor.note.delete',
2544 Deletes a note for the given user
2545 @param authtoken The login session key
2546 @param noteid The note id
2549 sub delete_user_note {
2550 my( $self, $conn, $authtoken, $noteid ) = @_;
2552 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2553 return $e->die_event unless $e->checkauth;
2554 my $note = $e->retrieve_actor_usr_note($noteid)
2555 or return $e->die_event;
2556 my $user = $e->retrieve_actor_user($note->usr)
2557 or return $e->die_event;
2558 return $e->die_event unless
2559 $e->allowed('UPDATE_USER', $user->home_ou);
2561 $e->delete_actor_usr_note($note) or return $e->die_event;
2567 __PACKAGE__->register_method (
2568 method => 'update_user_note',
2569 api_name => 'open-ils.actor.note.update',
2571 @param authtoken The login session key
2572 @param note The note
2576 sub update_user_note {
2577 my( $self, $conn, $auth, $note ) = @_;
2578 my $e = new_editor(authtoken=>$auth, xact=>1);
2579 return $e->event unless $e->checkauth;
2580 my $patron = $e->retrieve_actor_user($note->usr)
2581 or return $e->event;
2582 return $e->event unless
2583 $e->allowed('UPDATE_USER', $patron->home_ou);
2584 $e->update_actor_user_note($note)
2585 or return $e->event;
2593 __PACKAGE__->register_method (
2594 method => 'create_closed_date',
2595 api_name => 'open-ils.actor.org_unit.closed_date.create',
2597 Creates a new closing entry for the given org_unit
2598 @param authtoken The login session key
2599 @param note The closed_date object
2602 sub create_closed_date {
2603 my( $self, $conn, $authtoken, $cd ) = @_;
2605 my( $user, $evt ) = $U->checkses($authtoken);
2606 return $evt if $evt;
2608 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2609 return $evt if $evt;
2611 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2613 my $id = $U->storagereq(
2614 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2615 return $U->DB_UPDATE_FAILED($cd) unless $id;
2620 __PACKAGE__->register_method (
2621 method => 'delete_closed_date',
2622 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2624 Deletes a closing entry for the given org_unit
2625 @param authtoken The login session key
2626 @param noteid The close_date id
2629 sub delete_closed_date {
2630 my( $self, $conn, $authtoken, $cd ) = @_;
2632 my( $user, $evt ) = $U->checkses($authtoken);
2633 return $evt if $evt;
2636 ($cd_obj, $evt) = fetch_closed_date($cd);
2637 return $evt if $evt;
2639 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2640 return $evt if $evt;
2642 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2644 my $stat = $U->storagereq(
2645 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2646 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2651 __PACKAGE__->register_method(
2652 method => 'usrname_exists',
2653 api_name => 'open-ils.actor.username.exists',
2655 Returns the user ID of the requested username if that username exists, returns null otherwise
2659 # XXX Make me retun undef if no user has the ID
2661 sub usrname_exists {
2662 my( $self, $conn, $auth, $usrname ) = @_;
2663 my $e = new_editor(authtoken=>$auth);
2664 return $e->event unless $e->checkauth;
2665 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2666 return $$a[0] if $a and @$a;
2670 __PACKAGE__->register_method(
2671 method => 'barcode_exists',
2672 api_name => 'open-ils.actor.barcode.exists',
2674 Returns the user ID for the requested barcode if that barcode exists, returns null otherwise
2678 sub barcode_exists {
2679 my( $self, $conn, $auth, $barcode ) = @_;
2680 my $e = new_editor(authtoken=>$auth);
2681 return $e->event unless $e->checkauth;
2682 my $card = $e->search_actor_card({barcode => $barcode});
2683 return undef unless @$card;
2684 return $card->[0]->usr;
2688 __PACKAGE__->register_method(
2689 method => 'retrieve_net_levels',
2690 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2693 sub retrieve_net_levels {
2694 my( $self, $conn, $auth ) = @_;
2695 my $e = new_editor(authtoken=>$auth);
2696 return $e->event unless $e->checkauth;
2697 return $e->retrieve_all_config_net_access_level();
2701 __PACKAGE__->register_method(
2702 method => 'fetch_org_by_shortname',
2703 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2705 sub fetch_org_by_shortname {
2706 my( $self, $conn, $sname ) = @_;
2707 my $e = new_editor();
2708 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2709 return $e->event unless $org;
2714 __PACKAGE__->register_method(
2715 method => 'session_home_lib',
2716 api_name => 'open-ils.actor.session.home_lib',
2719 sub session_home_lib {
2720 my( $self, $conn, $auth ) = @_;
2721 my $e = new_editor(authtoken=>$auth);
2722 return undef unless $e->checkauth;
2723 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2724 return $org->shortname;
2727 __PACKAGE__->register_method(
2728 method => 'session_safe_token',
2729 api_name => 'open-ils.actor.session.safe_token',
2731 Returns a hashed session ID that is safe for export to the world.
2732 This safe token will expire after 1 hour of non-use.
2733 @param auth Active authentication token
2737 sub session_safe_token {
2738 my( $self, $conn, $auth ) = @_;
2739 my $e = new_editor(authtoken=>$auth);
2740 return undef unless $e->checkauth;
2742 my $safe_token = md5_hex($auth);
2744 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2746 # Add more like the following if needed...
2748 "safe-token-home_lib-shortname-$safe_token",
2749 $e->retrieve_actor_org_unit(
2750 $e->requestor->home_ou
2759 __PACKAGE__->register_method(
2760 method => 'safe_token_home_lib',
2761 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2763 Returns the home library shortname from the session
2764 asscociated with a safe token from generated by
2765 open-ils.actor.session.safe_token.
2766 @param safe_token Active safe token
2770 sub safe_token_home_lib {
2771 my( $self, $conn, $safe_token ) = @_;
2773 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2774 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2779 __PACKAGE__->register_method(
2780 method => 'slim_tree',
2781 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2784 my $tree = new_editor()->search_actor_org_unit(
2786 {"parent_ou" => undef },
2789 flesh_fields => { aou => ['children'] },
2790 order_by => { aou => 'name'},
2791 select => { aou => ["id","shortname", "name"]},
2796 return trim_tree($tree);
2802 return undef unless $tree;
2804 code => $tree->shortname,
2805 name => $tree->name,
2807 if( $tree->children and @{$tree->children} ) {
2808 $htree->{children} = [];
2809 for my $c (@{$tree->children}) {
2810 push( @{$htree->{children}}, trim_tree($c) );
2818 __PACKAGE__->register_method(
2819 method => "update_penalties",
2820 api_name => "open-ils.actor.user.penalties.update");
2821 sub update_penalties {
2822 my( $self, $conn, $auth, $userid ) = @_;
2823 my $e = new_editor(authtoken=>$auth);
2824 return $e->event unless $e->checkauth;
2825 $U->update_patron_penalties(
2827 patronid => $userid,
2834 __PACKAGE__->register_method(
2835 method => "user_retrieve_fleshed_by_id",
2836 api_name => "open-ils.actor.user.fleshed.retrieve",);
2838 sub user_retrieve_fleshed_by_id {
2839 my( $self, $client, $auth, $user_id, $fields ) = @_;
2840 my $e = new_editor(authtoken => $auth);
2841 return $e->event unless $e->checkauth;
2843 if( $e->requestor->id != $user_id ) {
2844 return $e->event unless $e->allowed('VIEW_USER');
2850 "standing_penalties",
2854 "stat_cat_entries" ];
2855 return new_flesh_user($user_id, $fields, $e);
2859 sub new_flesh_user {
2862 my $fields = shift || [];
2863 my $e = shift || new_editor(xact=>1);
2865 my $user = $e->retrieve_actor_user(
2870 "flesh_fields" => { "au" => $fields }
2873 ) or return $e->event;
2876 if( grep { $_ eq 'addresses' } @$fields ) {
2878 $user->addresses([]) unless @{$user->addresses};
2880 if( ref $user->billing_address ) {
2881 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2882 push( @{$user->addresses}, $user->billing_address );
2886 if( ref $user->mailing_address ) {
2887 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2888 push( @{$user->addresses}, $user->mailing_address );
2894 $user->clear_passwd();
2901 __PACKAGE__->register_method(
2902 method => "user_retrieve_parts",
2903 api_name => "open-ils.actor.user.retrieve.parts",);
2905 sub user_retrieve_parts {
2906 my( $self, $client, $auth, $user_id, $fields ) = @_;
2907 my $e = new_editor(authtoken => $auth);
2908 return $e->event unless $e->checkauth;
2909 if( $e->requestor->id != $user_id ) {
2910 return $e->event unless $e->allowed('VIEW_USER');
2913 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2914 push(@resp, $user->$_()) for(@$fields);
2920 __PACKAGE__->register_method(
2921 method => 'user_opt_in_enabled',
2922 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2924 @return 1 if user opt-in is globally enabled, 0 otherwise.
2927 sub user_opt_in_enabled {
2928 my($self, $conn) = @_;
2929 my $sc = OpenSRF::Utils::SettingsClient->new;
2930 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2935 __PACKAGE__->register_method(
2936 method => 'user_opt_in_at_org',
2937 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2939 @param $auth The auth token
2940 @param user_id The ID of the user to test
2941 @return 1 if the user has opted in at the specified org,
2942 event on error, and 0 otherwise. /);
2943 sub user_opt_in_at_org {
2944 my($self, $conn, $auth, $user_id) = @_;
2946 # see if we even need to enforce the opt-in value
2947 return 1 unless $self->user_opt_in_enabled;
2949 my $e = new_editor(authtoken => $auth);
2950 return $e->event unless $e->checkauth;
2951 my $org_id = $e->requestor->ws_ou;
2953 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2954 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2956 # user is automatically opted-in at the home org
2957 return 1 if $user->home_ou eq $org_id;
2959 my $vals = $e->search_actor_usr_org_unit_opt_in(
2960 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2966 __PACKAGE__->register_method(
2967 method => 'create_user_opt_in_at_org',
2968 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2970 @param $auth The auth token
2971 @param user_id The ID of the user to test
2972 @return The ID of the newly created object, event on error./);
2974 sub create_user_opt_in_at_org {
2975 my($self, $conn, $auth, $user_id) = @_;
2977 my $e = new_editor(authtoken => $auth, xact=>1);
2978 return $e->die_event unless $e->checkauth;
2979 my $org_id = $e->requestor->ws_ou;
2981 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2982 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2984 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2986 $opt_in->org_unit($org_id);
2987 $opt_in->usr($user_id);
2988 $opt_in->staff($e->requestor->id);
2989 $opt_in->opt_in_ts('now');
2990 $opt_in->opt_in_ws($e->requestor->wsid);
2992 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2993 or return $e->die_event;