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);
81 __PACKAGE__->register_method(
82 method => "set_ou_settings",
83 api_name => "open-ils.actor.org_unit.settings.update",
86 my( $self, $client, $auth, $org_id, $settings ) = @_;
88 my $e = new_editor(authtoken => $auth, xact => 1);
89 return $e->die_event unless $e->checkauth;
90 return $e->die_event unless $e->allowed('UPDATE_ORG_SETTING', $org_id);
92 for my $name (keys %$settings) {
93 my $val = $$settings{$name};
94 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
97 $val = OpenSRF::Utils::JSON->perl2JSON($val);
100 $e->update_actor_org_unit_setting($set) or return $e->die_event;
102 $set = Fieldmapper::actor::org_unit_setting->new;
103 $set->org_unit($org_id);
106 $e->create_actor_org_unit_setting($set) or return $e->die_event;
109 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
117 my $fetch_user_settings;
118 my $fetch_ou_settings;
120 __PACKAGE__->register_method(
121 method => "user_settings",
122 api_name => "open-ils.actor.patron.settings.retrieve",
125 my( $self, $client, $auth, $user_id, $setting ) = @_;
127 my $e = new_editor(authtoken => $auth);
128 return $e->event unless $e->checkauth;
130 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
131 if($e->requestor->id != $user_id) {
132 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
135 my $s = $e->search_actor_user_setting({usr => $user_id});
136 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
138 return $$settings{$setting} if $setting;
144 __PACKAGE__->register_method(
145 method => "ou_settings",
146 api_name => "open-ils.actor.org_unit.settings.retrieve",
149 my( $self, $client, $ouid ) = @_;
151 $logger->info("Fetching org unit settings for org $ouid");
153 my $s = $apputils->simplereq(
155 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
157 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
162 __PACKAGE__->register_method(
163 api_name => 'open-ils.actor.ou_setting.ancestor_default',
164 method => 'ou_ancestor_setting',
167 # ------------------------------------------------------------------
168 # Attempts to find the org setting value for a given org. if not
169 # found at the requested org, searches up the org tree until it
170 # finds a parent that has the requested setting.
171 # when found, returns { org => $id, value => $value }
172 # otherwise, returns NULL
173 # ------------------------------------------------------------------
174 sub ou_ancestor_setting {
175 my( $self, $client, $orgid, $name ) = @_;
176 return $U->ou_ancestor_setting($orgid, $name);
179 __PACKAGE__->register_method(
180 api_name => 'open-ils.actor.ou_setting.ancestor_default.batch',
181 method => 'ou_ancestor_setting_batch',
183 sub ou_ancestor_setting_batch {
184 my( $self, $client, $orgid, $name_list ) = @_;
186 $values{$_} = $U->ou_ancestor_setting($orgid, $_) for @$name_list;
193 __PACKAGE__->register_method (
194 method => "ou_setting_delete",
195 api_name => 'open-ils.actor.org_setting.delete',
197 Deletes a specific org unit setting for a specific location
198 @param authtoken The login session key
199 @param orgid The org unit whose setting we're changing
200 @param setting The name of the setting to delete
201 @return True value on success.
205 sub ou_setting_delete {
206 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
207 my( $reqr, $evt) = $U->checkses($authtoken);
209 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
212 my $id = $U->cstorereq(
213 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
214 { name => $setting, org_unit => $orgid } );
216 $logger->debug("Retrieved setting $id in org unit setting delete");
218 my $s = $U->cstorereq(
219 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
221 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
235 __PACKAGE__->register_method(
236 method => "update_patron",
237 api_name => "open-ils.actor.patron.update",);
240 my( $self, $client, $user_session, $patron ) = @_;
242 my $session = $apputils->start_db_session();
246 $logger->info("Creating new patron...") if $patron->isnew;
247 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
249 my( $user_obj, $evt ) = $U->checkses($user_session);
252 $evt = check_group_perm($session, $user_obj, $patron);
256 # $new_patron is the patron in progress. $patron is the original patron
257 # passed in with the method. new_patron will change as the components
258 # of patron are added/updated.
262 # unflesh the real items on the patron
263 $patron->card( $patron->card->id ) if(ref($patron->card));
264 $patron->billing_address( $patron->billing_address->id )
265 if(ref($patron->billing_address));
266 $patron->mailing_address( $patron->mailing_address->id )
267 if(ref($patron->mailing_address));
269 # create/update the patron first so we can use his id
270 if($patron->isnew()) {
271 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
273 } else { $new_patron = $patron; }
275 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
278 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
281 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
284 # re-update the patron if anything has happened to him during this process
285 if($new_patron->ischanged()) {
286 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
290 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
293 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
296 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
299 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
302 if(!$patron->isnew) {
303 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
306 $apputils->commit_db_session($session);
307 my $fuser = flesh_user($new_patron->id());
310 # Log the new and old patron for investigation
311 $logger->info("$user_session updating patron object. orig patron object = ".
312 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
322 return new_flesh_user($id, [
325 "standing_penalties",
329 "stat_cat_entries" ] );
337 # clone and clear stuff that would break the database
341 my $new_patron = $patron->clone;
343 $new_patron->clear_billing_address();
344 $new_patron->clear_mailing_address();
345 $new_patron->clear_addresses();
346 $new_patron->clear_card();
347 $new_patron->clear_cards();
348 $new_patron->clear_id();
349 $new_patron->clear_isnew();
350 $new_patron->clear_ischanged();
351 $new_patron->clear_isdeleted();
352 $new_patron->clear_stat_cat_entries();
353 $new_patron->clear_permissions();
354 $new_patron->clear_standing_penalties();
364 my $user_obj = shift;
366 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
367 return (undef, $evt) if $evt;
369 my $ex = $session->request(
370 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
372 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
375 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
377 my $id = $session->request(
378 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
379 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
381 $logger->info("Successfully created new user [$id] in DB");
383 return ( $session->request(
384 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
388 sub check_group_perm {
389 my( $session, $requestor, $patron ) = @_;
392 # first let's see if the requestor has
393 # priveleges to update this user in any way
394 if( ! $patron->isnew ) {
395 my $p = $session->request(
396 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
398 # If we are the requestor (trying to update our own account)
399 # and we are not trying to change our profile, we're good
400 if( $p->id == $requestor->id and
401 $p->profile == $patron->profile ) {
406 $evt = group_perm_failed($session, $requestor, $p);
410 # They are allowed to edit this patron.. can they put the
411 # patron into the group requested?
412 $evt = group_perm_failed($session, $requestor, $patron);
418 sub group_perm_failed {
419 my( $session, $requestor, $patron ) = @_;
423 my $grpid = $patron->profile;
427 $logger->debug("user update looking for group perm for group $grpid");
428 $grp = $session->request(
429 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
430 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
432 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
434 $logger->info("user update checking perm $perm on user ".
435 $requestor->id." for update/create on user username=".$patron->usrname);
437 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
445 my( $session, $patron, $user_obj, $noperm) = @_;
447 $logger->info("Updating patron ".$patron->id." in DB");
452 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
453 return (undef, $evt) if $evt;
456 # update the password by itself to avoid the password protection magic
457 if( $patron->passwd ) {
458 my $s = $session->request(
459 'open-ils.storage.direct.actor.user.remote_update',
460 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
461 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
462 $patron->clear_passwd;
465 if(!$patron->ident_type) {
466 $patron->clear_ident_type;
467 $patron->clear_ident_value;
470 $evt = verify_last_xact($session, $patron);
471 return (undef, $evt) if $evt;
473 my $stat = $session->request(
474 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
475 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
480 sub verify_last_xact {
481 my( $session, $patron ) = @_;
482 return undef unless $patron->id and $patron->id > 0;
483 my $p = $session->request(
484 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
485 my $xact = $p->last_xact_id;
486 return undef unless $xact;
487 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
488 return OpenILS::Event->new('XACT_COLLISION')
489 if $xact != $patron->last_xact_id;
494 sub _check_dup_ident {
495 my( $session, $patron ) = @_;
497 return undef unless $patron->ident_value;
500 ident_type => $patron->ident_type,
501 ident_value => $patron->ident_value,
504 $logger->debug("patron update searching for dup ident values: " .
505 $patron->ident_type . ':' . $patron->ident_value);
507 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
509 my $dups = $session->request(
510 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
513 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
520 sub _add_update_addresses {
524 my $new_patron = shift;
528 my $current_id; # id of the address before creation
530 for my $address (@{$patron->addresses()}) {
532 next unless ref $address;
533 $current_id = $address->id();
535 if( $patron->billing_address() and
536 $patron->billing_address() == $current_id ) {
537 $logger->info("setting billing addr to $current_id");
538 $new_patron->billing_address($address->id());
539 $new_patron->ischanged(1);
542 if( $patron->mailing_address() and
543 $patron->mailing_address() == $current_id ) {
544 $new_patron->mailing_address($address->id());
545 $logger->info("setting mailing addr to $current_id");
546 $new_patron->ischanged(1);
550 if($address->isnew()) {
552 $address->usr($new_patron->id());
554 ($address, $evt) = _add_address($session,$address);
555 return (undef, $evt) if $evt;
557 # we need to get the new id
558 if( $patron->billing_address() and
559 $patron->billing_address() == $current_id ) {
560 $new_patron->billing_address($address->id());
561 $logger->info("setting billing addr to $current_id");
562 $new_patron->ischanged(1);
565 if( $patron->mailing_address() and
566 $patron->mailing_address() == $current_id ) {
567 $new_patron->mailing_address($address->id());
568 $logger->info("setting mailing addr to $current_id");
569 $new_patron->ischanged(1);
572 } elsif($address->ischanged() ) {
574 ($address, $evt) = _update_address($session, $address);
575 return (undef, $evt) if $evt;
577 } elsif($address->isdeleted() ) {
579 if( $address->id() == $new_patron->mailing_address() ) {
580 $new_patron->clear_mailing_address();
581 ($new_patron, $evt) = _update_patron($session, $new_patron);
582 return (undef, $evt) if $evt;
585 if( $address->id() == $new_patron->billing_address() ) {
586 $new_patron->clear_billing_address();
587 ($new_patron, $evt) = _update_patron($session, $new_patron);
588 return (undef, $evt) if $evt;
591 $evt = _delete_address($session, $address);
592 return (undef, $evt) if $evt;
596 return ( $new_patron, undef );
600 # adds an address to the db and returns the address with new id
602 my($session, $address) = @_;
603 $address->clear_id();
605 $logger->info("Creating new address at street ".$address->street1);
607 # put the address into the database
608 my $id = $session->request(
609 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
610 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
613 return ($address, undef);
617 sub _update_address {
618 my( $session, $address ) = @_;
620 $logger->info("Updating address ".$address->id." in the DB");
622 my $stat = $session->request(
623 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
625 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
626 return ($address, undef);
631 sub _add_update_cards {
635 my $new_patron = shift;
639 my $virtual_id; #id of the card before creation
640 for my $card (@{$patron->cards()}) {
642 $card->usr($new_patron->id());
644 if(ref($card) and $card->isnew()) {
646 $virtual_id = $card->id();
647 ( $card, $evt ) = _add_card($session,$card);
648 return (undef, $evt) if $evt;
650 #if(ref($patron->card)) { $patron->card($patron->card->id); }
651 if($patron->card() == $virtual_id) {
652 $new_patron->card($card->id());
653 $new_patron->ischanged(1);
656 } elsif( ref($card) and $card->ischanged() ) {
657 $evt = _update_card($session, $card);
658 return (undef, $evt) if $evt;
662 return ( $new_patron, undef );
666 # adds an card to the db and returns the card with new id
668 my( $session, $card ) = @_;
671 $logger->info("Adding new patron card ".$card->barcode);
673 my $id = $session->request(
674 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
675 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
676 $logger->info("Successfully created patron card $id");
679 return ( $card, undef );
683 # returns event on error. returns undef otherwise
685 my( $session, $card ) = @_;
686 $logger->info("Updating patron card ".$card->id);
688 my $stat = $session->request(
689 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
690 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
697 # returns event on error. returns undef otherwise
698 sub _delete_address {
699 my( $session, $address ) = @_;
701 $logger->info("Deleting address ".$address->id." from DB");
703 my $stat = $session->request(
704 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
706 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
712 sub _add_survey_responses {
713 my ($session, $patron, $new_patron) = @_;
715 $logger->info( "Updating survey responses for patron ".$new_patron->id );
717 my $responses = $patron->survey_responses;
721 $_->usr($new_patron->id) for (@$responses);
723 my $evt = $U->simplereq( "open-ils.circ",
724 "open-ils.circ.survey.submit.user_id", $responses );
726 return (undef, $evt) if defined($U->event_code($evt));
730 return ( $new_patron, undef );
734 sub _create_stat_maps {
736 my($session, $user_session, $patron, $new_patron) = @_;
738 my $maps = $patron->stat_cat_entries();
740 for my $map (@$maps) {
742 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
744 if ($map->isdeleted()) {
745 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
747 } elsif ($map->isnew()) {
748 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
753 $map->target_usr($new_patron->id);
756 $logger->info("Updating stat entry with method $method and map $map");
758 my $stat = $session->request($method, $map)->gather(1);
759 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
763 return ($new_patron, undef);
766 sub _create_perm_maps {
768 my($session, $user_session, $patron, $new_patron) = @_;
770 my $maps = $patron->permissions;
772 for my $map (@$maps) {
774 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
775 if ($map->isdeleted()) {
776 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
777 } elsif ($map->isnew()) {
778 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
783 $map->usr($new_patron->id);
785 #warn( "Updating permissions with method $method and session $user_session and map $map" );
786 $logger->info( "Updating permissions with method $method and map $map" );
788 my $stat = $session->request($method, $map)->gather(1);
789 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
793 return ($new_patron, undef);
797 __PACKAGE__->register_method(
798 method => "set_user_work_ous",
799 api_name => "open-ils.actor.user.work_ous.update",
802 sub set_user_work_ous {
808 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
811 my $session = $apputils->start_db_session();
813 for my $map (@$maps) {
815 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
816 if ($map->isdeleted()) {
817 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
818 } elsif ($map->isnew()) {
819 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
823 #warn( "Updating permissions with method $method and session $ses and map $map" );
824 $logger->info( "Updating work_ou map with method $method and map $map" );
826 my $stat = $session->request($method, $map)->gather(1);
827 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
831 $apputils->commit_db_session($session);
833 return scalar(@$maps);
837 __PACKAGE__->register_method(
838 method => "set_user_perms",
839 api_name => "open-ils.actor.user.permissions.update",
848 my $session = $apputils->start_db_session();
850 my( $user_obj, $evt ) = $U->checkses($ses);
853 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
856 $all = 1 if ($U->is_true($user_obj->super_user()));
857 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
859 for my $map (@$maps) {
861 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
862 if ($map->isdeleted()) {
863 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
864 } elsif ($map->isnew()) {
865 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
869 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
870 #warn( "Updating permissions with method $method and session $ses and map $map" );
871 $logger->info( "Updating permissions with method $method and map $map" );
873 my $stat = $session->request($method, $map)->gather(1);
874 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
878 $apputils->commit_db_session($session);
880 return scalar(@$maps);
884 sub _create_standing_penalties {
886 my($session, $user_session, $patron, $new_patron) = @_;
888 my $maps = $patron->standing_penalties;
891 for my $map (@$maps) {
893 if ($map->isdeleted()) {
894 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
895 } elsif ($map->isnew()) {
896 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
902 $map->usr($new_patron->id);
904 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
906 my $stat = $session->request($method, $map)->gather(1);
907 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
910 return ($new_patron, undef);
915 __PACKAGE__->register_method(
916 method => "search_username",
917 api_name => "open-ils.actor.user.search.username",
920 sub search_username {
921 my($self, $client, $username) = @_;
922 return new_editor()->search_actor_user({usrname=>$username});
928 __PACKAGE__->register_method(
929 method => "user_retrieve_by_barcode",
931 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
933 sub user_retrieve_by_barcode {
934 my($self, $client, $user_session, $barcode) = @_;
936 $logger->debug("Searching for user with barcode $barcode");
937 my ($user_obj, $evt) = $apputils->checkses($user_session);
940 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
942 "open-ils.cstore.direct.actor.card.search.atomic",
943 { barcode => $barcode }
946 if(!$card || !$card->[0]) {
947 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
951 my $user = flesh_user($card->usr());
953 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
956 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
963 __PACKAGE__->register_method(
964 method => "get_user_by_id",
965 api_name => "open-ils.actor.user.retrieve",);
968 my ($self, $client, $auth, $id) = @_;
969 my $e = new_editor(authtoken=>$auth);
970 return $e->event unless $e->checkauth;
971 my $user = $e->retrieve_actor_user($id)
973 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
979 __PACKAGE__->register_method(
980 method => "get_org_types",
981 api_name => "open-ils.actor.org_types.retrieve",);
984 return $U->get_org_types();
989 __PACKAGE__->register_method(
990 method => "get_user_ident_types",
991 api_name => "open-ils.actor.user.ident_types.retrieve",
994 sub get_user_ident_types {
995 return $ident_types if $ident_types;
996 return $ident_types =
997 new_editor()->retrieve_all_config_identification_type();
1003 __PACKAGE__->register_method(
1004 method => "get_org_unit",
1005 api_name => "open-ils.actor.org_unit.retrieve",
1009 my( $self, $client, $user_session, $org_id ) = @_;
1010 my $e = new_editor(authtoken => $user_session);
1012 return $e->event unless $e->checkauth;
1013 $org_id = $e->requestor->ws_ou;
1015 my $o = $e->retrieve_actor_org_unit($org_id)
1016 or return $e->event;
1020 __PACKAGE__->register_method(
1021 method => "search_org_unit",
1022 api_name => "open-ils.actor.org_unit_list.search",
1025 sub search_org_unit {
1027 my( $self, $client, $field, $value ) = @_;
1029 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1031 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1032 { $field => $value } );
1038 # build the org tree
1040 __PACKAGE__->register_method(
1041 method => "get_org_tree",
1042 api_name => "open-ils.actor.org_tree.retrieve",
1044 note => "Returns the entire org tree structure",
1050 return $U->get_org_tree($client->session->session_locale);
1054 __PACKAGE__->register_method(
1055 method => "get_org_descendants",
1056 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1059 # depth is optional. org_unit is the id
1060 sub get_org_descendants {
1061 my( $self, $client, $org_unit, $depth ) = @_;
1063 if(ref $org_unit eq 'ARRAY') {
1066 for my $i (0..scalar(@$org_unit)-1) {
1067 my $list = $U->simple_scalar_request(
1069 "open-ils.storage.actor.org_unit.descendants.atomic",
1070 $org_unit->[$i], $depth->[$i] );
1071 push(@trees, $U->build_org_tree($list));
1076 my $orglist = $apputils->simple_scalar_request(
1078 "open-ils.storage.actor.org_unit.descendants.atomic",
1079 $org_unit, $depth );
1080 return $U->build_org_tree($orglist);
1085 __PACKAGE__->register_method(
1086 method => "get_org_ancestors",
1087 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1090 # depth is optional. org_unit is the id
1091 sub get_org_ancestors {
1092 my( $self, $client, $org_unit, $depth ) = @_;
1093 my $orglist = $apputils->simple_scalar_request(
1095 "open-ils.storage.actor.org_unit.ancestors.atomic",
1096 $org_unit, $depth );
1097 return $U->build_org_tree($orglist);
1101 __PACKAGE__->register_method(
1102 method => "get_standings",
1103 api_name => "open-ils.actor.standings.retrieve"
1108 return $user_standings if $user_standings;
1109 return $user_standings =
1110 $apputils->simple_scalar_request(
1112 "open-ils.cstore.direct.config.standing.search.atomic",
1113 { id => { "!=" => undef } }
1119 __PACKAGE__->register_method(
1120 method => "get_my_org_path",
1121 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1124 sub get_my_org_path {
1125 my( $self, $client, $auth, $org_id ) = @_;
1126 my $e = new_editor(authtoken=>$auth);
1127 return $e->event unless $e->checkauth;
1128 $org_id = $e->requestor->ws_ou unless defined $org_id;
1130 return $apputils->simple_scalar_request(
1132 "open-ils.storage.actor.org_unit.full_path.atomic",
1137 __PACKAGE__->register_method(
1138 method => "patron_adv_search",
1139 api_name => "open-ils.actor.patron.search.advanced" );
1140 sub patron_adv_search {
1141 my( $self, $client, $auth, $search_hash,
1142 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1144 my $e = new_editor(authtoken=>$auth);
1145 return $e->event unless $e->checkauth;
1146 return $e->event unless $e->allowed('VIEW_USER');
1147 return $U->storagereq(
1148 "open-ils.storage.actor.user.crazy_search", $search_hash,
1149 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1153 __PACKAGE__->register_method(
1154 method => "update_passwd",
1156 api_name => "open-ils.actor.user.password.update");
1158 __PACKAGE__->register_method(
1159 method => "update_passwd",
1160 api_name => "open-ils.actor.user.username.update");
1162 __PACKAGE__->register_method(
1163 method => "update_passwd",
1164 api_name => "open-ils.actor.user.email.update");
1167 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1168 my $e = new_editor(xact=>1, authtoken=>$auth);
1169 return $e->die_event unless $e->checkauth;
1171 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1172 or return $e->die_event;
1173 my $api = $self->api_name;
1175 if( $api =~ /password/o ) {
1177 # make sure the original password matches the in-database password
1178 return OpenILS::Event->new('INCORRECT_PASSWORD')
1179 if md5_hex($orig_pw) ne $db_user->passwd;
1180 $db_user->passwd($new_val);
1184 # if we don't clear the password, the user will be updated with
1185 # a hashed version of the hashed version of their password
1186 $db_user->clear_passwd;
1188 if( $api =~ /username/o ) {
1190 # make sure no one else has this username
1191 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1192 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1193 $db_user->usrname($new_val);
1195 } elsif( $api =~ /email/o ) {
1196 $db_user->email($new_val);
1200 $e->update_actor_user($db_user) or return $e->die_event;
1208 __PACKAGE__->register_method(
1209 method => "check_user_perms",
1210 api_name => "open-ils.actor.user.perm.check",
1211 notes => <<" NOTES");
1212 Takes a login session, user id, an org id, and an array of perm type strings. For each
1213 perm type, if the user does *not* have the given permission it is added
1214 to a list which is returned from the method. If all permissions
1215 are allowed, an empty list is returned
1216 if the logged in user does not match 'user_id', then the logged in user must
1217 have VIEW_PERMISSION priveleges.
1220 sub check_user_perms {
1221 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1223 my( $staff, $evt ) = $apputils->checkses($login_session);
1224 return $evt if $evt;
1226 if($staff->id ne $user_id) {
1227 if( $evt = $apputils->check_perms(
1228 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1234 for my $perm (@$perm_types) {
1235 if($apputils->check_perms($user_id, $org_id, $perm)) {
1236 push @not_allowed, $perm;
1240 return \@not_allowed
1243 __PACKAGE__->register_method(
1244 method => "check_user_perms2",
1245 api_name => "open-ils.actor.user.perm.check.multi_org",
1247 Checks the permissions on a list of perms and orgs for a user
1248 @param authtoken The login session key
1249 @param user_id The id of the user to check
1250 @param orgs The array of org ids
1251 @param perms The array of permission names
1252 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1253 if the logged in user does not match 'user_id', then the logged in user must
1254 have VIEW_PERMISSION priveleges.
1257 sub check_user_perms2 {
1258 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1260 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1261 $authtoken, $user_id, 'VIEW_PERMISSION' );
1262 return $evt if $evt;
1265 for my $org (@$orgs) {
1266 for my $perm (@$perms) {
1267 if($apputils->check_perms($user_id, $org, $perm)) {
1268 push @not_allowed, [ $org, $perm ];
1273 return \@not_allowed
1277 __PACKAGE__->register_method(
1278 method => 'check_user_perms3',
1279 api_name => 'open-ils.actor.user.perm.highest_org',
1281 Returns the highest org unit id at which a user has a given permission
1282 If the requestor does not match the target user, the requestor must have
1283 'VIEW_PERMISSION' rights at the home org unit of the target user
1284 @param authtoken The login session key
1285 @param userid The id of the user in question
1286 @param perm The permission to check
1287 @return The org unit highest in the org tree within which the user has
1288 the requested permission
1291 sub check_user_perms3 {
1292 my($self, $client, $authtoken, $user_id, $perm) = @_;
1293 my $e = new_editor(authtoken=>$authtoken);
1294 return $e->event unless $e->checkauth;
1296 my $tree = $self->get_org_tree();
1298 unless($e->requestor->id == $user_id) {
1299 my $user = $e->retrieve_actor_user($user_id)
1300 or return $e->event;
1301 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1302 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1305 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1309 __PACKAGE__->register_method(
1310 method => 'check_user_work_perms',
1311 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1315 Returns a set of org units which represent the highest orgs in
1316 the org tree where the user has the requested permission. The
1317 purpose of this method is to return the smallest set of org units
1318 which represent the full expanse of the user's ability to perform
1319 the requested action. The user whose perms this method should
1320 check is implied by the authtoken. /,
1322 {desc => 'authtoken', type => 'string'},
1323 {desc => 'permission name', type => 'string'},
1324 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1326 return => {desc => 'An array of org IDs'}
1330 __PACKAGE__->register_method(
1331 method => 'check_user_work_perms',
1332 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1335 @see open-ils.actor.user.work_perm.highest_org_set
1336 Returns a list of org trees. The root of each tree
1337 is the highest org in the organization hierarchy where the user has the
1338 requested permission. Below each tree root is its full tree of descendants.
1342 __PACKAGE__->register_method(
1343 method => 'check_user_work_perms',
1344 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1347 @see open-ils.actor.user.work_perm.highest_org_set
1348 Returns a list of list of all of the org_units where the user
1349 has the requested permission. The first item in each list
1350 is the highest permission org for that section of the
1351 org tree. The remaining items in each sub-list are the
1352 descendants of that org.
1357 __PACKAGE__->register_method(
1358 method => 'check_user_work_perms',
1359 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1362 @see open-ils.actor.user.work_perm.highest_org_set
1363 Returns a list of lists of all of the org_unit IDs where the user
1364 has the requested permission. The first item in each list
1365 is the highest permission org for that section of the
1366 org tree. The remaining items in each sub-list are the
1367 descendants of that org.
1371 __PACKAGE__->register_method(
1372 method => 'check_user_work_perms_batch',
1373 api_name => 'open-ils.actor.user.work_perm.highest_org_set.batch',
1376 __PACKAGE__->register_method(
1377 method => 'check_user_work_perms_batch',
1378 api_name => 'open-ils.actor.user.work_perm.org_tree_list.batch',
1381 __PACKAGE__->register_method(
1382 method => 'check_user_work_perms_batch',
1383 api_name => 'open-ils.actor.user.work_perm.org_unit_list.batch',
1386 __PACKAGE__->register_method(
1387 method => 'check_user_work_perms_batch',
1388 api_name => 'open-ils.actor.user.work_perm.org_id_list.batch',
1393 sub check_user_work_perms {
1394 my($self, $conn, $auth, $perm, $options) = @_;
1395 my $e = new_editor(authtoken=>$auth);
1396 return $e->event unless $e->checkauth;
1397 return check_user_work_perms_impl($self, $conn, $e, $perm, $options);
1400 sub check_user_work_perms_batch {
1401 my($self, $conn, $auth, $perm_list, $options) = @_;
1402 my $e = new_editor(authtoken=>$auth);
1403 return $e->event unless $e->checkauth;
1405 $map->{$_} = check_user_work_perms_impl($self, $conn, $e, $_, $options) for @$perm_list;
1409 sub check_user_work_perms_impl {
1410 my($self, $conn, $e, $perm, $options) = @_;
1411 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1413 return $orglist if $self->api_name =~ /highest_org_set/;
1415 # build a list of org trees
1416 return get_org_descendants($self, $conn, $orglist)
1417 if $self->api_name =~ /org_tree_list/;
1420 for my $orgid (@$orglist) {
1421 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1422 unshift @sublist, $orgid; # make sure it's at the front of the list
1423 if($self->api_name =~ /org_id_list/) {
1424 push(@list, @sublist);
1426 push(@list, @{$e->batch_retrieve_actor_org_unit(\@sublist)});
1434 __PACKAGE__->register_method(
1435 method => 'check_user_perms4',
1436 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1438 Returns the highest org unit id at which a user has a given permission
1439 If the requestor does not match the target user, the requestor must have
1440 'VIEW_PERMISSION' rights at the home org unit of the target user
1441 @param authtoken The login session key
1442 @param userid The id of the user in question
1443 @param perms An array of perm names to check
1444 @return An array of orgId's representing the org unit
1445 highest in the org tree within which the user has the requested permission
1446 The arrah of orgId's has matches the order of the perms array
1449 sub check_user_perms4 {
1450 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1452 my( $staff, $target, $org, $evt );
1454 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1455 $authtoken, $userid, 'VIEW_PERMISSION' );
1456 return $evt if $evt;
1459 return [] unless ref($perms);
1460 my $tree = $U->get_org_tree();
1462 for my $p (@$perms) {
1463 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1471 __PACKAGE__->register_method(
1472 method => "user_fines_summary",
1473 api_name => "open-ils.actor.user.fines.summary",
1475 notes => <<" NOTES");
1476 Returns a short summary of the users total open fines, excluding voided fines
1477 Params are login_session, user_id
1478 Returns a 'mous' object.
1481 sub user_fines_summary {
1482 my( $self, $client, $auth, $user_id ) = @_;
1483 my $e = new_editor(authtoken=>$auth);
1484 return $e->event unless $e->checkauth;
1485 my $user = $e->retrieve_actor_user($user_id)
1486 or return $e->event;
1488 if( $user_id ne $e->requestor->id ) {
1489 return $e->event unless
1490 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1493 # run this inside a transaction to prevent replication delay errors
1494 my $ses = $U->start_db_session();
1495 my $s = $ses->request(
1496 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1497 $U->rollback_db_session($ses);
1504 __PACKAGE__->register_method(
1505 method => "user_transactions",
1506 api_name => "open-ils.actor.user.transactions",
1507 notes => <<" NOTES");
1508 Returns a list of open user transactions (mbts objects);
1509 Params are login_session, user_id
1510 Optional third parameter is the transactions type. defaults to all
1513 __PACKAGE__->register_method(
1514 method => "user_transactions",
1515 api_name => "open-ils.actor.user.transactions.have_charge",
1516 notes => <<" NOTES");
1517 Returns a list of all open user transactions (mbts objects) that have an initial charge
1518 Params are login_session, user_id
1519 Optional third parameter is the transactions type. defaults to all
1522 __PACKAGE__->register_method(
1523 method => "user_transactions",
1524 api_name => "open-ils.actor.user.transactions.have_balance",
1525 notes => <<" NOTES");
1526 Returns a list of all open user transactions (mbts objects) that have a balance
1527 Params are login_session, user_id
1528 Optional third parameter is the transactions type. defaults to all
1531 __PACKAGE__->register_method(
1532 method => "user_transactions",
1533 api_name => "open-ils.actor.user.transactions.fleshed",
1534 notes => <<" NOTES");
1535 Returns an object/hash of transaction, circ, title where transaction = an open
1536 user transactions (mbts objects), circ is the attached circluation, and title
1537 is the title the circ points to
1538 Params are login_session, user_id
1539 Optional third parameter is the transactions type. defaults to all
1542 __PACKAGE__->register_method(
1543 method => "user_transactions",
1544 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1545 notes => <<" NOTES");
1546 Returns an object/hash of transaction, circ, title where transaction = an open
1547 user transactions that has an initial charge (mbts objects), circ is the
1548 attached circluation, and title is the title the circ points to
1549 Params are login_session, user_id
1550 Optional third parameter is the transactions type. defaults to all
1553 __PACKAGE__->register_method(
1554 method => "user_transactions",
1555 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1556 notes => <<" NOTES");
1557 Returns an object/hash of transaction, circ, title where transaction = an open
1558 user transaction that has a balance (mbts objects), circ is the attached
1559 circluation, and title is the title the circ points to
1560 Params are login_session, user_id
1561 Optional third parameter is the transaction type. defaults to all
1564 __PACKAGE__->register_method(
1565 method => "user_transactions",
1566 api_name => "open-ils.actor.user.transactions.count",
1567 notes => <<" NOTES");
1568 Returns an object/hash of transaction, circ, title where transaction = an open
1569 user transactions (mbts objects), circ is the attached circluation, and title
1570 is the title the circ points to
1571 Params are login_session, user_id
1572 Optional third parameter is the transactions type. defaults to all
1575 __PACKAGE__->register_method(
1576 method => "user_transactions",
1577 api_name => "open-ils.actor.user.transactions.have_charge.count",
1578 notes => <<" NOTES");
1579 Returns an object/hash of transaction, circ, title where transaction = an open
1580 user transactions that has an initial charge (mbts objects), circ is the
1581 attached circluation, and title is the title the circ points to
1582 Params are login_session, user_id
1583 Optional third parameter is the transactions type. defaults to all
1586 __PACKAGE__->register_method(
1587 method => "user_transactions",
1588 api_name => "open-ils.actor.user.transactions.have_balance.count",
1589 notes => <<" NOTES");
1590 Returns an object/hash of transaction, circ, title where transaction = an open
1591 user transaction that has a balance (mbts objects), circ is the attached
1592 circluation, and title is the title the circ points to
1593 Params are login_session, user_id
1594 Optional third parameter is the transaction type. defaults to all
1597 __PACKAGE__->register_method(
1598 method => "user_transactions",
1599 api_name => "open-ils.actor.user.transactions.have_balance.total",
1600 notes => <<" NOTES");
1601 Returns an object/hash of transaction, circ, title where transaction = an open
1602 user transaction that has a balance (mbts objects), circ is the attached
1603 circluation, and title is the title the circ points to
1604 Params are login_session, user_id
1605 Optional third parameter is the transaction type. defaults to all
1610 sub user_transactions {
1611 my( $self, $client, $login_session, $user_id, $type ) = @_;
1613 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1614 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1615 return $evt if $evt;
1617 my $api = $self->api_name();
1621 if(defined($type)) { @xact = (xact_type => $type);
1623 } else { @xact = (); }
1626 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1627 ->run($login_session => $user_id => $type);
1629 if($api =~ /have_charge/o) {
1631 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1633 } elsif($api =~ /have_balance/o) {
1635 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1638 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1642 if($api =~ /total/o) {
1644 for my $t (@$trans) {
1645 $total += $t->balance_owed;
1648 $logger->debug("Total balance owed by user $user_id: $total");
1652 if($api =~ /count/o) { return scalar @$trans; }
1653 if($api !~ /fleshed/o) { return $trans; }
1656 for my $t (@$trans) {
1658 if( $t->xact_type ne 'circulation' ) {
1659 push @resp, {transaction => $t};
1663 my $circ = $apputils->simple_scalar_request(
1665 "open-ils.cstore.direct.action.circulation.retrieve",
1670 my $title = $apputils->simple_scalar_request(
1672 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1673 $circ->target_copy );
1677 my $u = OpenILS::Utils::ModsParser->new();
1678 $u->start_mods_batch($title->marc());
1679 my $mods = $u->finish_mods_batch();
1680 $mods->doc_id($title->id) if $mods;
1682 push @resp, {transaction => $t, circ => $circ, record => $mods };
1690 __PACKAGE__->register_method(
1691 method => "user_transaction_retrieve",
1692 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1694 notes => <<" NOTES");
1695 Returns a fleshedtransaction record
1697 __PACKAGE__->register_method(
1698 method => "user_transaction_retrieve",
1699 api_name => "open-ils.actor.user.transaction.retrieve",
1701 notes => <<" NOTES");
1702 Returns a transaction record
1704 sub user_transaction_retrieve {
1705 my( $self, $client, $login_session, $bill_id ) = @_;
1707 # XXX I think I'm deprecated... make sure
1709 my $trans = $apputils->simple_scalar_request(
1711 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1715 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1716 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1717 return $evt if $evt;
1719 my $api = $self->api_name();
1720 if($api !~ /fleshed/o) { return $trans; }
1722 if( $trans->xact_type ne 'circulation' ) {
1723 $logger->debug("Returning non-circ transaction");
1724 return {transaction => $trans};
1727 my $circ = $apputils->simple_scalar_request(
1729 "open-ils..direct.action.circulation.retrieve",
1732 return {transaction => $trans} unless $circ;
1733 $logger->debug("Found the circ transaction");
1735 my $title = $apputils->simple_scalar_request(
1737 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1738 $circ->target_copy );
1740 return {transaction => $trans, circ => $circ } unless $title;
1741 $logger->debug("Found the circ title");
1745 my $u = OpenILS::Utils::ModsParser->new();
1746 $u->start_mods_batch($title->marc());
1747 $mods = $u->finish_mods_batch();
1749 if ($title->id == OILS_PRECAT_RECORD) {
1750 my $copy = $apputils->simple_scalar_request(
1752 "open-ils.cstore.direct.asset.copy.retrieve",
1753 $circ->target_copy );
1755 $mods = new Fieldmapper::metabib::virtual_record;
1756 $mods->doc_id(OILS_PRECAT_RECORD);
1757 $mods->title($copy->dummy_title);
1758 $mods->author($copy->dummy_author);
1762 $logger->debug("MODSized the circ title");
1764 return {transaction => $trans, circ => $circ, record => $mods };
1768 __PACKAGE__->register_method(
1769 method => "hold_request_count",
1770 api_name => "open-ils.actor.user.hold_requests.count",
1773 notes => <<" NOTES");
1774 Returns hold ready/total counts
1776 sub hold_request_count {
1777 my( $self, $client, $login_session, $userid ) = @_;
1779 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1780 $login_session, $userid, 'VIEW_HOLD' );
1781 return $evt if $evt;
1784 my $holds = $apputils->simple_scalar_request(
1786 "open-ils.cstore.direct.action.hold_request.search.atomic",
1789 fulfillment_time => {"=" => undef },
1790 cancel_time => undef,
1795 for my $h (@$holds) {
1796 next unless $h->capture_time and $h->current_copy;
1798 my $copy = $apputils->simple_scalar_request(
1800 "open-ils.cstore.direct.asset.copy.retrieve",
1804 if ($copy and $copy->status == 8) {
1809 return { total => scalar(@$holds), ready => scalar(@ready) };
1813 __PACKAGE__->register_method(
1814 method => "checkedout_count",
1815 api_name => "open-ils.actor.user.checked_out.count__",
1817 notes => <<" NOTES");
1818 Returns a transaction record
1822 sub checkedout_count {
1823 my( $self, $client, $login_session, $userid ) = @_;
1825 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1826 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1827 return $evt if $evt;
1829 my $circs = $apputils->simple_scalar_request(
1831 "open-ils.cstore.direct.action.circulation.search.atomic",
1832 { usr => $userid, stop_fines => undef }
1833 #{ usr => $userid, checkin_time => {"=" => undef } }
1836 my $parser = DateTime::Format::ISO8601->new;
1839 for my $c (@$circs) {
1840 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1841 my $due = $due_dt->epoch;
1843 if ($due < DateTime->today->epoch) {
1848 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1852 __PACKAGE__->register_method(
1853 method => "checked_out",
1854 api_name => "open-ils.actor.user.checked_out",
1858 Returns a structure of circulations objects sorted by
1859 out, overdue, lost, claims_returned, long_overdue.
1860 A list of IDs are returned of each type.
1861 lost, long_overdue, and claims_returned circ will not
1862 be "finished" (there is an outstanding balance or some
1863 other pending action on the circ).
1865 The .count method also includes a 'total' field which
1866 sums all "open" circs
1870 __PACKAGE__->register_method(
1871 method => "checked_out",
1872 api_name => "open-ils.actor.user.checked_out.count",
1875 signature => q/@see open-ils.actor.user.checked_out/
1879 my( $self, $conn, $auth, $userid ) = @_;
1881 my $e = new_editor(authtoken=>$auth);
1882 return $e->event unless $e->checkauth;
1884 if( $userid ne $e->requestor->id ) {
1885 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1888 my $count = $self->api_name =~ /count/;
1889 return _checked_out( $count, $e, $userid );
1893 my( $iscount, $e, $userid ) = @_;
1894 my $meth = 'open-ils.storage.actor.user.checked_out';
1895 $meth = "$meth.count" if $iscount;
1896 return $U->storagereq($meth, $userid);
1900 sub _checked_out_WHAT {
1901 my( $iscount, $e, $userid ) = @_;
1903 my $circs = $e->search_action_circulation(
1904 { usr => $userid, stop_fines => undef });
1906 my $mcircs = $e->search_action_circulation(
1909 checkin_time => undef,
1910 xact_finish => undef,
1914 push( @$circs, @$mcircs );
1916 my $parser = DateTime::Format::ISO8601->new;
1918 # split the circs up into overdue and not-overdue circs
1920 for my $c (@$circs) {
1921 if( $c->due_date ) {
1922 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1923 my $due = $due_dt->epoch;
1924 if ($due < DateTime->today->epoch) {
1925 push @overdue, $c->id;
1934 # grab all of the lost, claims-returned, and longoverdue circs
1935 #my $open = $e->search_action_circulation(
1936 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1939 # these items have stop_fines, but no xact_finish, so money
1940 # is owed on them and they have not been checked in
1941 my $open = $e->search_action_circulation(
1944 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1945 xact_finish => undef,
1946 checkin_time => undef,
1951 my( @lost, @cr, @lo );
1952 for my $c (@$open) {
1953 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1954 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1955 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1961 total => @$circs + @lost + @cr + @lo,
1962 out => scalar(@out),
1963 overdue => scalar(@overdue),
1964 lost => scalar(@lost),
1965 claims_returned => scalar(@cr),
1966 long_overdue => scalar(@lo)
1972 overdue => \@overdue,
1974 claims_returned => \@cr,
1975 long_overdue => \@lo
1981 __PACKAGE__->register_method(
1982 method => "checked_in_with_fines",
1983 api_name => "open-ils.actor.user.checked_in_with_fines",
1986 signature => q/@see open-ils.actor.user.checked_out/
1988 sub checked_in_with_fines {
1989 my( $self, $conn, $auth, $userid ) = @_;
1991 my $e = new_editor(authtoken=>$auth);
1992 return $e->event unless $e->checkauth;
1994 if( $userid ne $e->requestor->id ) {
1995 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1998 # money is owed on these items and they are checked in
1999 my $open = $e->search_action_circulation(
2002 xact_finish => undef,
2003 checkin_time => { "!=" => undef },
2008 my( @lost, @cr, @lo );
2009 for my $c (@$open) {
2010 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2011 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2012 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2017 claims_returned => \@cr,
2018 long_overdue => \@lo
2030 __PACKAGE__->register_method(
2031 method => "user_transaction_history",
2032 api_name => "open-ils.actor.user.transactions.history",
2034 notes => <<" NOTES");
2035 Returns a list of billable transaction ids for a user, optionally by type
2037 __PACKAGE__->register_method(
2038 method => "user_transaction_history",
2039 api_name => "open-ils.actor.user.transactions.history.have_charge",
2041 notes => <<" NOTES");
2042 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2044 __PACKAGE__->register_method(
2045 method => "user_transaction_history",
2046 api_name => "open-ils.actor.user.transactions.history.have_balance",
2049 notes => <<" NOTES");
2050 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2052 __PACKAGE__->register_method(
2053 method => "user_transaction_history",
2054 api_name => "open-ils.actor.user.transactions.history.still_open",
2056 notes => <<" NOTES");
2057 Returns a list of billable transaction ids for a user that are not finished
2059 __PACKAGE__->register_method(
2060 method => "user_transaction_history",
2061 api_name => "open-ils.actor.user.transactions.history.have_bill",
2064 notes => <<" NOTES");
2065 Returns a list of billable transaction ids for a user that has billings
2068 sub user_transaction_history {
2069 my( $self, $conn, $auth, $userid, $type ) = @_;
2071 # run inside of a transaction to prevent replication delays
2072 my $e = new_editor(xact=>1, authtoken=>$auth);
2073 return $e->die_event unless $e->checkauth;
2075 if( $e->requestor->id ne $userid ) {
2076 return $e->die_event
2077 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2080 my $api = $self->api_name;
2081 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2083 my @xacts = @{ $e->search_money_billable_transaction(
2084 [ { usr => $userid, @xact_finish },
2086 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2087 order_by => { mbt => 'xact_start DESC' },
2095 #my @mbts = _make_mbts( @xacts );
2096 my @mbts = $U->make_mbts( @xacts );
2098 if(defined($type)) {
2099 @mbts = grep { $_->xact_type eq $type } @mbts;
2102 if($api =~ /have_balance/o) {
2103 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2106 if($api =~ /have_charge/o) {
2107 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2110 if($api =~ /have_bill/o) {
2111 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2119 __PACKAGE__->register_method(
2120 method => "user_perms",
2121 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2123 notes => <<" NOTES");
2124 Returns a list of permissions
2127 my( $self, $client, $authtoken, $user ) = @_;
2129 my( $staff, $evt ) = $apputils->checkses($authtoken);
2130 return $evt if $evt;
2132 $user ||= $staff->id;
2134 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2138 return $apputils->simple_scalar_request(
2140 "open-ils.storage.permission.user_perms.atomic",
2144 __PACKAGE__->register_method(
2145 method => "retrieve_perms",
2146 api_name => "open-ils.actor.permissions.retrieve",
2147 notes => <<" NOTES");
2148 Returns a list of permissions
2150 sub retrieve_perms {
2151 my( $self, $client ) = @_;
2152 return $apputils->simple_scalar_request(
2154 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2155 { id => { '!=' => undef } }
2159 __PACKAGE__->register_method(
2160 method => "retrieve_groups",
2161 api_name => "open-ils.actor.groups.retrieve",
2162 notes => <<" NOTES");
2163 Returns a list of user groupss
2165 sub retrieve_groups {
2166 my( $self, $client ) = @_;
2167 return new_editor()->retrieve_all_permission_grp_tree();
2170 __PACKAGE__->register_method(
2171 method => "retrieve_org_address",
2172 api_name => "open-ils.actor.org_unit.address.retrieve",
2173 notes => <<' NOTES');
2174 Returns an org_unit address by ID
2175 @param An org_address ID
2177 sub retrieve_org_address {
2178 my( $self, $client, $id ) = @_;
2179 return $apputils->simple_scalar_request(
2181 "open-ils.cstore.direct.actor.org_address.retrieve",
2186 __PACKAGE__->register_method(
2187 method => "retrieve_groups_tree",
2188 api_name => "open-ils.actor.groups.tree.retrieve",
2189 notes => <<" NOTES");
2190 Returns a list of user groups
2192 sub retrieve_groups_tree {
2193 my( $self, $client ) = @_;
2194 return new_editor()->search_permission_grp_tree(
2199 flesh_fields => { pgt => ["children"] },
2200 order_by => { pgt => 'name'}
2207 __PACKAGE__->register_method(
2208 method => "add_user_to_groups",
2209 api_name => "open-ils.actor.user.set_groups",
2210 notes => <<" NOTES");
2211 Adds a user to one or more permission groups
2214 sub add_user_to_groups {
2215 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2217 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2218 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2219 return $evt if $evt;
2221 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2222 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2223 return $evt if $evt;
2225 $apputils->simplereq(
2227 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2229 for my $group (@$groups) {
2230 my $link = Fieldmapper::permission::usr_grp_map->new;
2232 $link->usr($userid);
2234 my $id = $apputils->simplereq(
2236 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2242 __PACKAGE__->register_method(
2243 method => "get_user_perm_groups",
2244 api_name => "open-ils.actor.user.get_groups",
2245 notes => <<" NOTES");
2246 Retrieve a user's permission groups.
2250 sub get_user_perm_groups {
2251 my( $self, $client, $authtoken, $userid ) = @_;
2253 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2254 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2255 return $evt if $evt;
2257 return $apputils->simplereq(
2259 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2263 __PACKAGE__->register_method(
2264 method => "get_user_work_ous",
2265 api_name => "open-ils.actor.user.get_work_ous",
2266 notes => <<" NOTES");
2267 Retrieve a user's work org units.
2269 __PACKAGE__->register_method(
2270 method => "get_user_work_ous",
2271 api_name => "open-ils.actor.user.get_work_ous.ids",
2272 notes => <<" NOTES");
2273 Retrieve a user's work org units.
2277 sub get_user_work_ous {
2278 my( $self, $client, $auth, $userid ) = @_;
2279 my $e = new_editor(authtoken=>$auth);
2280 return $e->event unless $e->checkauth;
2281 $userid ||= $e->requestor->id;
2283 if($e->requestor->id != $userid) {
2284 my $user = $e->retrieve_actor_user($userid)
2285 or return $e->event;
2286 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2289 return $e->search_permission_usr_work_ou_map({usr => $userid})
2290 unless $self->api_name =~ /.ids$/;
2292 # client just wants a list of org IDs
2293 return $U->get_user_work_ou_ids($e, $userid);
2299 __PACKAGE__->register_method (
2300 method => 'register_workstation',
2301 api_name => 'open-ils.actor.workstation.register.override',
2302 signature => q/@see open-ils.actor.workstation.register/);
2304 __PACKAGE__->register_method (
2305 method => 'register_workstation',
2306 api_name => 'open-ils.actor.workstation.register',
2308 Registers a new workstion in the system
2309 @param authtoken The login session key
2310 @param name The name of the workstation id
2311 @param owner The org unit that owns this workstation
2312 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2313 if the name is already in use.
2316 sub register_workstation {
2317 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2319 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2320 return $e->die_event unless $e->checkauth;
2321 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2322 my $existing = $e->search_actor_workstation({name => $name})->[0];
2326 if( $self->api_name =~ /override/o ) {
2327 # workstation with the given name exists.
2329 if($owner ne $existing->owning_lib) {
2330 # if necessary, update the owning_lib of the workstation
2332 $logger->info("changing owning lib of workstation ".$existing->id.
2333 " from ".$existing->owning_lib." to $owner");
2334 return $e->die_event unless
2335 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2337 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2339 $existing->owning_lib($owner);
2340 return $e->die_event unless $e->update_actor_workstation($existing);
2346 "attempt to register an existing workstation. returning existing ID");
2349 return $existing->id;
2352 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2356 my $ws = Fieldmapper::actor::workstation->new;
2357 $ws->owning_lib($owner);
2359 $e->create_actor_workstation($ws) or return $e->die_event;
2361 return $ws->id; # note: editor sets the id on the new object for us
2364 __PACKAGE__->register_method (
2365 method => 'workstation_list',
2366 api_name => 'open-ils.actor.workstation.list',
2368 Returns a list of workstations registered at the given location
2369 @param authtoken The login session key
2370 @param ids A list of org_unit.id's for the workstation owners
2373 sub workstation_list {
2374 my( $self, $conn, $authtoken, @orgs ) = @_;
2376 my $e = new_editor(authtoken=>$authtoken);
2377 return $e->event unless $e->checkauth;
2382 unless $e->allowed('REGISTER_WORKSTATION', $o);
2383 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2394 __PACKAGE__->register_method (
2395 method => 'fetch_patron_note',
2396 api_name => 'open-ils.actor.note.retrieve.all',
2399 Returns a list of notes for a given user
2400 Requestor must have VIEW_USER permission if pub==false and
2401 @param authtoken The login session key
2402 @param args Hash of params including
2403 patronid : the patron's id
2404 pub : true if retrieving only public notes
2408 sub fetch_patron_note {
2409 my( $self, $conn, $authtoken, $args ) = @_;
2410 my $patronid = $$args{patronid};
2412 my($reqr, $evt) = $U->checkses($authtoken);
2413 return $evt if $evt;
2416 ($patron, $evt) = $U->fetch_user($patronid);
2417 return $evt if $evt;
2420 if( $patronid ne $reqr->id ) {
2421 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2422 return $evt if $evt;
2424 return $U->cstorereq(
2425 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2426 { usr => $patronid, pub => 't' } );
2429 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2430 return $evt if $evt;
2432 return $U->cstorereq(
2433 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2436 __PACKAGE__->register_method (
2437 method => 'create_user_note',
2438 api_name => 'open-ils.actor.note.create',
2440 Creates a new note for the given user
2441 @param authtoken The login session key
2442 @param note The note object
2445 sub create_user_note {
2446 my( $self, $conn, $authtoken, $note ) = @_;
2447 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2448 return $e->die_event unless $e->checkauth;
2450 my $user = $e->retrieve_actor_user($note->usr)
2451 or return $e->die_event;
2453 return $e->die_event unless
2454 $e->allowed('UPDATE_USER',$user->home_ou);
2456 $note->creator($e->requestor->id);
2457 $e->create_actor_usr_note($note) or return $e->die_event;
2463 __PACKAGE__->register_method (
2464 method => 'delete_user_note',
2465 api_name => 'open-ils.actor.note.delete',
2467 Deletes a note for the given user
2468 @param authtoken The login session key
2469 @param noteid The note id
2472 sub delete_user_note {
2473 my( $self, $conn, $authtoken, $noteid ) = @_;
2475 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2476 return $e->die_event unless $e->checkauth;
2477 my $note = $e->retrieve_actor_usr_note($noteid)
2478 or return $e->die_event;
2479 my $user = $e->retrieve_actor_user($note->usr)
2480 or return $e->die_event;
2481 return $e->die_event unless
2482 $e->allowed('UPDATE_USER', $user->home_ou);
2484 $e->delete_actor_usr_note($note) or return $e->die_event;
2490 __PACKAGE__->register_method (
2491 method => 'update_user_note',
2492 api_name => 'open-ils.actor.note.update',
2494 @param authtoken The login session key
2495 @param note The note
2499 sub update_user_note {
2500 my( $self, $conn, $auth, $note ) = @_;
2501 my $e = new_editor(authtoken=>$auth, xact=>1);
2502 return $e->event unless $e->checkauth;
2503 my $patron = $e->retrieve_actor_user($note->usr)
2504 or return $e->event;
2505 return $e->event unless
2506 $e->allowed('UPDATE_USER', $patron->home_ou);
2507 $e->update_actor_user_note($note)
2508 or return $e->event;
2516 __PACKAGE__->register_method (
2517 method => 'create_closed_date',
2518 api_name => 'open-ils.actor.org_unit.closed_date.create',
2520 Creates a new closing entry for the given org_unit
2521 @param authtoken The login session key
2522 @param note The closed_date object
2525 sub create_closed_date {
2526 my( $self, $conn, $authtoken, $cd ) = @_;
2528 my( $user, $evt ) = $U->checkses($authtoken);
2529 return $evt if $evt;
2531 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2532 return $evt if $evt;
2534 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2536 my $id = $U->storagereq(
2537 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2538 return $U->DB_UPDATE_FAILED($cd) unless $id;
2543 __PACKAGE__->register_method (
2544 method => 'delete_closed_date',
2545 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2547 Deletes a closing entry for the given org_unit
2548 @param authtoken The login session key
2549 @param noteid The close_date id
2552 sub delete_closed_date {
2553 my( $self, $conn, $authtoken, $cd ) = @_;
2555 my( $user, $evt ) = $U->checkses($authtoken);
2556 return $evt if $evt;
2559 ($cd_obj, $evt) = fetch_closed_date($cd);
2560 return $evt if $evt;
2562 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2563 return $evt if $evt;
2565 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2567 my $stat = $U->storagereq(
2568 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2569 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2574 __PACKAGE__->register_method(
2575 method => 'usrname_exists',
2576 api_name => 'open-ils.actor.username.exists',
2578 Returns 1 if the requested username exists, returns 0 otherwise
2582 sub usrname_exists {
2583 my( $self, $conn, $auth, $usrname ) = @_;
2584 my $e = new_editor(authtoken=>$auth);
2585 return $e->event unless $e->checkauth;
2586 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2587 return $$a[0] if $a and @$a;
2591 __PACKAGE__->register_method(
2592 method => 'barcode_exists',
2593 api_name => 'open-ils.actor.barcode.exists',
2596 Returns 1 if the requested barcode exists, returns 0 otherwise
2600 sub barcode_exists {
2601 my( $self, $conn, $auth, $barcode ) = @_;
2602 my $e = new_editor(authtoken=>$auth);
2603 return $e->event unless $e->checkauth;
2604 my $card = $e->search_actor_card({barcode => $barcode});
2605 return undef unless @$card;
2606 return $card->[0]->usr;
2610 __PACKAGE__->register_method(
2611 method => 'retrieve_net_levels',
2612 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2615 sub retrieve_net_levels {
2616 my( $self, $conn, $auth ) = @_;
2617 my $e = new_editor(authtoken=>$auth);
2618 return $e->event unless $e->checkauth;
2619 return $e->retrieve_all_config_net_access_level();
2623 __PACKAGE__->register_method(
2624 method => 'fetch_org_by_shortname',
2625 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2627 sub fetch_org_by_shortname {
2628 my( $self, $conn, $sname ) = @_;
2629 my $e = new_editor();
2630 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2631 return $e->event unless $org;
2636 __PACKAGE__->register_method(
2637 method => 'session_home_lib',
2638 api_name => 'open-ils.actor.session.home_lib',
2641 sub session_home_lib {
2642 my( $self, $conn, $auth ) = @_;
2643 my $e = new_editor(authtoken=>$auth);
2644 return undef unless $e->checkauth;
2645 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2646 return $org->shortname;
2649 __PACKAGE__->register_method(
2650 method => 'session_safe_token',
2651 api_name => 'open-ils.actor.session.safe_token',
2653 Returns a hashed session ID that is safe for export to the world.
2654 This safe token will expire after 1 hour of non-use.
2655 @param auth Active authentication token
2659 sub session_safe_token {
2660 my( $self, $conn, $auth ) = @_;
2661 my $e = new_editor(authtoken=>$auth);
2662 return undef unless $e->checkauth;
2664 my $safe_token = md5_hex($auth);
2666 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2668 # Add more like the following if needed...
2670 "safe-token-home_lib-shortname-$safe_token",
2671 $e->retrieve_actor_org_unit(
2672 $e->requestor->home_ou
2681 __PACKAGE__->register_method(
2682 method => 'safe_token_home_lib',
2683 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2685 Returns the home library shortname from the session
2686 asscociated with a safe token from generated by
2687 open-ils.actor.session.safe_token.
2688 @param safe_token Active safe token
2692 sub safe_token_home_lib {
2693 my( $self, $conn, $safe_token ) = @_;
2695 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2696 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2701 __PACKAGE__->register_method(
2702 method => 'slim_tree',
2703 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2706 my $tree = new_editor()->search_actor_org_unit(
2708 {"parent_ou" => undef },
2711 flesh_fields => { aou => ['children'] },
2712 order_by => { aou => 'name'},
2713 select => { aou => ["id","shortname", "name"]},
2718 return trim_tree($tree);
2724 return undef unless $tree;
2726 code => $tree->shortname,
2727 name => $tree->name,
2729 if( $tree->children and @{$tree->children} ) {
2730 $htree->{children} = [];
2731 for my $c (@{$tree->children}) {
2732 push( @{$htree->{children}}, trim_tree($c) );
2740 __PACKAGE__->register_method(
2741 method => "update_penalties",
2742 api_name => "open-ils.actor.user.penalties.update");
2743 sub update_penalties {
2744 my( $self, $conn, $auth, $userid ) = @_;
2745 my $e = new_editor(authtoken=>$auth);
2746 return $e->event unless $e->checkauth;
2747 $U->update_patron_penalties(
2749 patronid => $userid,
2756 __PACKAGE__->register_method(
2757 method => "user_retrieve_fleshed_by_id",
2758 api_name => "open-ils.actor.user.fleshed.retrieve",);
2760 sub user_retrieve_fleshed_by_id {
2761 my( $self, $client, $auth, $user_id, $fields ) = @_;
2762 my $e = new_editor(authtoken => $auth);
2763 return $e->event unless $e->checkauth;
2765 if( $e->requestor->id != $user_id ) {
2766 return $e->event unless $e->allowed('VIEW_USER');
2772 "standing_penalties",
2776 "stat_cat_entries" ];
2777 return new_flesh_user($user_id, $fields, $e);
2781 sub new_flesh_user {
2784 my $fields = shift || [];
2785 my $e = shift || new_editor(xact=>1);
2787 my $user = $e->retrieve_actor_user(
2792 "flesh_fields" => { "au" => $fields }
2795 ) or return $e->event;
2798 if( grep { $_ eq 'addresses' } @$fields ) {
2800 $user->addresses([]) unless @{$user->addresses};
2802 if( ref $user->billing_address ) {
2803 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2804 push( @{$user->addresses}, $user->billing_address );
2808 if( ref $user->mailing_address ) {
2809 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2810 push( @{$user->addresses}, $user->mailing_address );
2816 $user->clear_passwd();
2823 __PACKAGE__->register_method(
2824 method => "user_retrieve_parts",
2825 api_name => "open-ils.actor.user.retrieve.parts",);
2827 sub user_retrieve_parts {
2828 my( $self, $client, $auth, $user_id, $fields ) = @_;
2829 my $e = new_editor(authtoken => $auth);
2830 return $e->event unless $e->checkauth;
2831 if( $e->requestor->id != $user_id ) {
2832 return $e->event unless $e->allowed('VIEW_USER');
2835 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2836 push(@resp, $user->$_()) for(@$fields);
2842 __PACKAGE__->register_method(
2843 method => 'user_opt_in_enabled',
2844 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2846 @return 1 if user opt-in is globally enabled, 0 otherwise.
2849 sub user_opt_in_enabled {
2850 my($self, $conn) = @_;
2851 my $sc = OpenSRF::Utils::SettingsClient->new;
2852 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2857 __PACKAGE__->register_method(
2858 method => 'user_opt_in_at_org',
2859 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2861 @param $auth The auth token
2862 @param user_id The ID of the user to test
2863 @return 1 if the user has opted in at the specified org,
2864 event on error, and 0 otherwise. /);
2865 sub user_opt_in_at_org {
2866 my($self, $conn, $auth, $user_id) = @_;
2868 # see if we even need to enforce the opt-in value
2869 return 1 unless user_opt_in_enabled($self);
2871 my $e = new_editor(authtoken => $auth);
2872 return $e->event unless $e->checkauth;
2873 my $org_id = $e->requestor->ws_ou;
2875 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2876 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2878 # user is automatically opted-in at the home org
2879 return 1 if $user->home_ou eq $org_id;
2881 my $vals = $e->search_actor_usr_org_unit_opt_in(
2882 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2888 __PACKAGE__->register_method(
2889 method => 'create_user_opt_in_at_org',
2890 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2892 @param $auth The auth token
2893 @param user_id The ID of the user to test
2894 @return The ID of the newly created object, event on error./);
2896 sub create_user_opt_in_at_org {
2897 my($self, $conn, $auth, $user_id) = @_;
2899 my $e = new_editor(authtoken => $auth, xact=>1);
2900 return $e->die_event unless $e->checkauth;
2901 my $org_id = $e->requestor->ws_ou;
2903 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2904 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2906 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2908 $opt_in->org_unit($org_id);
2909 $opt_in->usr($user_id);
2910 $opt_in->staff($e->requestor->id);
2911 $opt_in->opt_in_ts('now');
2912 $opt_in->opt_in_ws($e->requestor->wsid);
2914 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2915 or return $e->die_event;
2923 __PACKAGE__->register_method (
2924 method => 'retrieve_org_hours',
2925 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
2927 Returns the hours of operation for a specified org unit
2928 @param authtoken The login session key
2929 @param org_id The org_unit ID
2933 sub retrieve_org_hours {
2934 my($self, $conn, $auth, $org_id) = @_;
2935 my $e = new_editor(authtoken => $auth);
2936 return $e->die_event unless $e->checkauth;
2937 $org_id ||= $e->requestor->ws_ou;
2938 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);