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;
91 for my $name (keys %$settings) {
92 my $val = $$settings{$name};
93 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
95 return $e->die_event unless $e->allowed("UPDATE_ORG_UNIT_SETTING.$name", $org_id);
98 $val = OpenSRF::Utils::JSON->perl2JSON($val);
101 $e->update_actor_org_unit_setting($set) or return $e->die_event;
103 $set = Fieldmapper::actor::org_unit_setting->new;
104 $set->org_unit($org_id);
107 $e->create_actor_org_unit_setting($set) or return $e->die_event;
110 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
118 my $fetch_user_settings;
119 my $fetch_ou_settings;
121 __PACKAGE__->register_method(
122 method => "user_settings",
123 api_name => "open-ils.actor.patron.settings.retrieve",
126 my( $self, $client, $auth, $user_id, $setting ) = @_;
128 my $e = new_editor(authtoken => $auth);
129 return $e->event unless $e->checkauth;
131 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
132 if($e->requestor->id != $user_id) {
133 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
136 my $s = $e->search_actor_user_setting({usr => $user_id});
137 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
139 return $$settings{$setting} if $setting;
145 __PACKAGE__->register_method(
146 method => "ou_settings",
147 api_name => "open-ils.actor.org_unit.settings.retrieve",
150 my( $self, $client, $ouid ) = @_;
152 $logger->info("Fetching org unit settings for org $ouid");
154 my $s = $apputils->simplereq(
156 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
158 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
163 __PACKAGE__->register_method(
164 api_name => 'open-ils.actor.ou_setting.ancestor_default',
165 method => 'ou_ancestor_setting',
168 # ------------------------------------------------------------------
169 # Attempts to find the org setting value for a given org. if not
170 # found at the requested org, searches up the org tree until it
171 # finds a parent that has the requested setting.
172 # when found, returns { org => $id, value => $value }
173 # otherwise, returns NULL
174 # ------------------------------------------------------------------
175 sub ou_ancestor_setting {
176 my( $self, $client, $orgid, $name ) = @_;
177 return $U->ou_ancestor_setting($orgid, $name);
180 __PACKAGE__->register_method(
181 api_name => 'open-ils.actor.ou_setting.ancestor_default.batch',
182 method => 'ou_ancestor_setting_batch',
184 sub ou_ancestor_setting_batch {
185 my( $self, $client, $orgid, $name_list ) = @_;
187 $values{$_} = $U->ou_ancestor_setting($orgid, $_) for @$name_list;
194 __PACKAGE__->register_method (
195 method => "ou_setting_delete",
196 api_name => 'open-ils.actor.org_setting.delete',
198 Deletes a specific org unit setting for a specific location
199 @param authtoken The login session key
200 @param orgid The org unit whose setting we're changing
201 @param setting The name of the setting to delete
202 @return True value on success.
206 sub ou_setting_delete {
207 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
208 my( $reqr, $evt) = $U->checkses($authtoken);
210 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
213 my $id = $U->cstorereq(
214 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
215 { name => $setting, org_unit => $orgid } );
217 $logger->debug("Retrieved setting $id in org unit setting delete");
219 my $s = $U->cstorereq(
220 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
222 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
236 __PACKAGE__->register_method(
237 method => "update_patron",
238 api_name => "open-ils.actor.patron.update",);
241 my( $self, $client, $user_session, $patron ) = @_;
243 my $session = $apputils->start_db_session();
247 $logger->info("Creating new patron...") if $patron->isnew;
248 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
250 my( $user_obj, $evt ) = $U->checkses($user_session);
253 $evt = check_group_perm($session, $user_obj, $patron);
257 # $new_patron is the patron in progress. $patron is the original patron
258 # passed in with the method. new_patron will change as the components
259 # of patron are added/updated.
263 # unflesh the real items on the patron
264 $patron->card( $patron->card->id ) if(ref($patron->card));
265 $patron->billing_address( $patron->billing_address->id )
266 if(ref($patron->billing_address));
267 $patron->mailing_address( $patron->mailing_address->id )
268 if(ref($patron->mailing_address));
270 # create/update the patron first so we can use his id
271 if($patron->isnew()) {
272 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
274 } else { $new_patron = $patron; }
276 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
279 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
282 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
285 # re-update the patron if anything has happened to him during this process
286 if($new_patron->ischanged()) {
287 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
291 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
294 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
297 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
300 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
303 if(!$patron->isnew) {
304 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
307 $apputils->commit_db_session($session);
308 my $fuser = flesh_user($new_patron->id());
311 # Log the new and old patron for investigation
312 $logger->info("$user_session updating patron object. orig patron object = ".
313 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
323 return new_flesh_user($id, [
326 "standing_penalties",
330 "stat_cat_entries" ] );
338 # clone and clear stuff that would break the database
342 my $new_patron = $patron->clone;
344 $new_patron->clear_billing_address();
345 $new_patron->clear_mailing_address();
346 $new_patron->clear_addresses();
347 $new_patron->clear_card();
348 $new_patron->clear_cards();
349 $new_patron->clear_id();
350 $new_patron->clear_isnew();
351 $new_patron->clear_ischanged();
352 $new_patron->clear_isdeleted();
353 $new_patron->clear_stat_cat_entries();
354 $new_patron->clear_permissions();
355 $new_patron->clear_standing_penalties();
365 my $user_obj = shift;
367 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
368 return (undef, $evt) if $evt;
370 my $ex = $session->request(
371 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
373 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
376 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
378 my $id = $session->request(
379 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
380 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
382 $logger->info("Successfully created new user [$id] in DB");
384 return ( $session->request(
385 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
389 sub check_group_perm {
390 my( $session, $requestor, $patron ) = @_;
393 # first let's see if the requestor has
394 # priveleges to update this user in any way
395 if( ! $patron->isnew ) {
396 my $p = $session->request(
397 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
399 # If we are the requestor (trying to update our own account)
400 # and we are not trying to change our profile, we're good
401 if( $p->id == $requestor->id and
402 $p->profile == $patron->profile ) {
407 $evt = group_perm_failed($session, $requestor, $p);
411 # They are allowed to edit this patron.. can they put the
412 # patron into the group requested?
413 $evt = group_perm_failed($session, $requestor, $patron);
419 sub group_perm_failed {
420 my( $session, $requestor, $patron ) = @_;
424 my $grpid = $patron->profile;
428 $logger->debug("user update looking for group perm for group $grpid");
429 $grp = $session->request(
430 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
431 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
433 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
435 $logger->info("user update checking perm $perm on user ".
436 $requestor->id." for update/create on user username=".$patron->usrname);
438 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
446 my( $session, $patron, $user_obj, $noperm) = @_;
448 $logger->info("Updating patron ".$patron->id." in DB");
453 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
454 return (undef, $evt) if $evt;
457 # update the password by itself to avoid the password protection magic
458 if( $patron->passwd ) {
459 my $s = $session->request(
460 'open-ils.storage.direct.actor.user.remote_update',
461 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
462 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
463 $patron->clear_passwd;
466 if(!$patron->ident_type) {
467 $patron->clear_ident_type;
468 $patron->clear_ident_value;
471 $evt = verify_last_xact($session, $patron);
472 return (undef, $evt) if $evt;
474 my $stat = $session->request(
475 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
476 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
481 sub verify_last_xact {
482 my( $session, $patron ) = @_;
483 return undef unless $patron->id and $patron->id > 0;
484 my $p = $session->request(
485 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
486 my $xact = $p->last_xact_id;
487 return undef unless $xact;
488 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
489 return OpenILS::Event->new('XACT_COLLISION')
490 if $xact != $patron->last_xact_id;
495 sub _check_dup_ident {
496 my( $session, $patron ) = @_;
498 return undef unless $patron->ident_value;
501 ident_type => $patron->ident_type,
502 ident_value => $patron->ident_value,
505 $logger->debug("patron update searching for dup ident values: " .
506 $patron->ident_type . ':' . $patron->ident_value);
508 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
510 my $dups = $session->request(
511 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
514 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
521 sub _add_update_addresses {
525 my $new_patron = shift;
529 my $current_id; # id of the address before creation
531 for my $address (@{$patron->addresses()}) {
533 next unless ref $address;
534 $current_id = $address->id();
536 if( $patron->billing_address() and
537 $patron->billing_address() == $current_id ) {
538 $logger->info("setting billing addr to $current_id");
539 $new_patron->billing_address($address->id());
540 $new_patron->ischanged(1);
543 if( $patron->mailing_address() and
544 $patron->mailing_address() == $current_id ) {
545 $new_patron->mailing_address($address->id());
546 $logger->info("setting mailing addr to $current_id");
547 $new_patron->ischanged(1);
551 if($address->isnew()) {
553 $address->usr($new_patron->id());
555 ($address, $evt) = _add_address($session,$address);
556 return (undef, $evt) if $evt;
558 # we need to get the new id
559 if( $patron->billing_address() and
560 $patron->billing_address() == $current_id ) {
561 $new_patron->billing_address($address->id());
562 $logger->info("setting billing addr to $current_id");
563 $new_patron->ischanged(1);
566 if( $patron->mailing_address() and
567 $patron->mailing_address() == $current_id ) {
568 $new_patron->mailing_address($address->id());
569 $logger->info("setting mailing addr to $current_id");
570 $new_patron->ischanged(1);
573 } elsif($address->ischanged() ) {
575 ($address, $evt) = _update_address($session, $address);
576 return (undef, $evt) if $evt;
578 } elsif($address->isdeleted() ) {
580 if( $address->id() == $new_patron->mailing_address() ) {
581 $new_patron->clear_mailing_address();
582 ($new_patron, $evt) = _update_patron($session, $new_patron);
583 return (undef, $evt) if $evt;
586 if( $address->id() == $new_patron->billing_address() ) {
587 $new_patron->clear_billing_address();
588 ($new_patron, $evt) = _update_patron($session, $new_patron);
589 return (undef, $evt) if $evt;
592 $evt = _delete_address($session, $address);
593 return (undef, $evt) if $evt;
597 return ( $new_patron, undef );
601 # adds an address to the db and returns the address with new id
603 my($session, $address) = @_;
604 $address->clear_id();
606 $logger->info("Creating new address at street ".$address->street1);
608 # put the address into the database
609 my $id = $session->request(
610 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
611 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
614 return ($address, undef);
618 sub _update_address {
619 my( $session, $address ) = @_;
621 $logger->info("Updating address ".$address->id." in the DB");
623 my $stat = $session->request(
624 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
626 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
627 return ($address, undef);
632 sub _add_update_cards {
636 my $new_patron = shift;
640 my $virtual_id; #id of the card before creation
641 for my $card (@{$patron->cards()}) {
643 $card->usr($new_patron->id());
645 if(ref($card) and $card->isnew()) {
647 $virtual_id = $card->id();
648 ( $card, $evt ) = _add_card($session,$card);
649 return (undef, $evt) if $evt;
651 #if(ref($patron->card)) { $patron->card($patron->card->id); }
652 if($patron->card() == $virtual_id) {
653 $new_patron->card($card->id());
654 $new_patron->ischanged(1);
657 } elsif( ref($card) and $card->ischanged() ) {
658 $evt = _update_card($session, $card);
659 return (undef, $evt) if $evt;
663 return ( $new_patron, undef );
667 # adds an card to the db and returns the card with new id
669 my( $session, $card ) = @_;
672 $logger->info("Adding new patron card ".$card->barcode);
674 my $id = $session->request(
675 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
676 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
677 $logger->info("Successfully created patron card $id");
680 return ( $card, undef );
684 # returns event on error. returns undef otherwise
686 my( $session, $card ) = @_;
687 $logger->info("Updating patron card ".$card->id);
689 my $stat = $session->request(
690 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
691 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
698 # returns event on error. returns undef otherwise
699 sub _delete_address {
700 my( $session, $address ) = @_;
702 $logger->info("Deleting address ".$address->id." from DB");
704 my $stat = $session->request(
705 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
707 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
713 sub _add_survey_responses {
714 my ($session, $patron, $new_patron) = @_;
716 $logger->info( "Updating survey responses for patron ".$new_patron->id );
718 my $responses = $patron->survey_responses;
722 $_->usr($new_patron->id) for (@$responses);
724 my $evt = $U->simplereq( "open-ils.circ",
725 "open-ils.circ.survey.submit.user_id", $responses );
727 return (undef, $evt) if defined($U->event_code($evt));
731 return ( $new_patron, undef );
735 sub _create_stat_maps {
737 my($session, $user_session, $patron, $new_patron) = @_;
739 my $maps = $patron->stat_cat_entries();
741 for my $map (@$maps) {
743 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
745 if ($map->isdeleted()) {
746 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
748 } elsif ($map->isnew()) {
749 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
754 $map->target_usr($new_patron->id);
757 $logger->info("Updating stat entry with method $method and map $map");
759 my $stat = $session->request($method, $map)->gather(1);
760 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
764 return ($new_patron, undef);
767 sub _create_perm_maps {
769 my($session, $user_session, $patron, $new_patron) = @_;
771 my $maps = $patron->permissions;
773 for my $map (@$maps) {
775 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
776 if ($map->isdeleted()) {
777 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
778 } elsif ($map->isnew()) {
779 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
784 $map->usr($new_patron->id);
786 #warn( "Updating permissions with method $method and session $user_session and map $map" );
787 $logger->info( "Updating permissions with method $method and map $map" );
789 my $stat = $session->request($method, $map)->gather(1);
790 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
794 return ($new_patron, undef);
798 __PACKAGE__->register_method(
799 method => "set_user_work_ous",
800 api_name => "open-ils.actor.user.work_ous.update",
803 sub set_user_work_ous {
809 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
812 my $session = $apputils->start_db_session();
814 for my $map (@$maps) {
816 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
817 if ($map->isdeleted()) {
818 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
819 } elsif ($map->isnew()) {
820 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
824 #warn( "Updating permissions with method $method and session $ses and map $map" );
825 $logger->info( "Updating work_ou map with method $method and map $map" );
827 my $stat = $session->request($method, $map)->gather(1);
828 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
832 $apputils->commit_db_session($session);
834 return scalar(@$maps);
838 __PACKAGE__->register_method(
839 method => "set_user_perms",
840 api_name => "open-ils.actor.user.permissions.update",
849 my $session = $apputils->start_db_session();
851 my( $user_obj, $evt ) = $U->checkses($ses);
854 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
857 $all = 1 if ($U->is_true($user_obj->super_user()));
858 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
860 for my $map (@$maps) {
862 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
863 if ($map->isdeleted()) {
864 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
865 } elsif ($map->isnew()) {
866 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
870 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
871 #warn( "Updating permissions with method $method and session $ses and map $map" );
872 $logger->info( "Updating permissions with method $method and map $map" );
874 my $stat = $session->request($method, $map)->gather(1);
875 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
879 $apputils->commit_db_session($session);
881 return scalar(@$maps);
885 sub _create_standing_penalties {
887 my($session, $user_session, $patron, $new_patron) = @_;
889 my $maps = $patron->standing_penalties;
892 for my $map (@$maps) {
894 if ($map->isdeleted()) {
895 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
896 } elsif ($map->isnew()) {
897 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
903 $map->usr($new_patron->id);
905 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
907 my $stat = $session->request($method, $map)->gather(1);
908 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
911 return ($new_patron, undef);
916 __PACKAGE__->register_method(
917 method => "search_username",
918 api_name => "open-ils.actor.user.search.username",
921 sub search_username {
922 my($self, $client, $username) = @_;
923 return new_editor()->search_actor_user({usrname=>$username});
929 __PACKAGE__->register_method(
930 method => "user_retrieve_by_barcode",
932 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
934 sub user_retrieve_by_barcode {
935 my($self, $client, $user_session, $barcode) = @_;
937 $logger->debug("Searching for user with barcode $barcode");
938 my ($user_obj, $evt) = $apputils->checkses($user_session);
941 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
943 "open-ils.cstore.direct.actor.card.search.atomic",
944 { barcode => $barcode }
947 if(!$card || !$card->[0]) {
948 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
952 my $user = flesh_user($card->usr());
954 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
957 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
964 __PACKAGE__->register_method(
965 method => "get_user_by_id",
966 api_name => "open-ils.actor.user.retrieve",);
969 my ($self, $client, $auth, $id) = @_;
970 my $e = new_editor(authtoken=>$auth);
971 return $e->event unless $e->checkauth;
972 my $user = $e->retrieve_actor_user($id)
974 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
980 __PACKAGE__->register_method(
981 method => "get_org_types",
982 api_name => "open-ils.actor.org_types.retrieve",);
985 return $U->get_org_types();
990 __PACKAGE__->register_method(
991 method => "get_user_ident_types",
992 api_name => "open-ils.actor.user.ident_types.retrieve",
995 sub get_user_ident_types {
996 return $ident_types if $ident_types;
997 return $ident_types =
998 new_editor()->retrieve_all_config_identification_type();
1004 __PACKAGE__->register_method(
1005 method => "get_org_unit",
1006 api_name => "open-ils.actor.org_unit.retrieve",
1010 my( $self, $client, $user_session, $org_id ) = @_;
1011 my $e = new_editor(authtoken => $user_session);
1013 return $e->event unless $e->checkauth;
1014 $org_id = $e->requestor->ws_ou;
1016 my $o = $e->retrieve_actor_org_unit($org_id)
1017 or return $e->event;
1021 __PACKAGE__->register_method(
1022 method => "search_org_unit",
1023 api_name => "open-ils.actor.org_unit_list.search",
1026 sub search_org_unit {
1028 my( $self, $client, $field, $value ) = @_;
1030 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1032 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1033 { $field => $value } );
1039 # build the org tree
1041 __PACKAGE__->register_method(
1042 method => "get_org_tree",
1043 api_name => "open-ils.actor.org_tree.retrieve",
1045 note => "Returns the entire org tree structure",
1051 return $U->get_org_tree($client->session->session_locale);
1055 __PACKAGE__->register_method(
1056 method => "get_org_descendants",
1057 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1060 # depth is optional. org_unit is the id
1061 sub get_org_descendants {
1062 my( $self, $client, $org_unit, $depth ) = @_;
1064 if(ref $org_unit eq 'ARRAY') {
1067 for my $i (0..scalar(@$org_unit)-1) {
1068 my $list = $U->simple_scalar_request(
1070 "open-ils.storage.actor.org_unit.descendants.atomic",
1071 $org_unit->[$i], $depth->[$i] );
1072 push(@trees, $U->build_org_tree($list));
1077 my $orglist = $apputils->simple_scalar_request(
1079 "open-ils.storage.actor.org_unit.descendants.atomic",
1080 $org_unit, $depth );
1081 return $U->build_org_tree($orglist);
1086 __PACKAGE__->register_method(
1087 method => "get_org_ancestors",
1088 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1091 # depth is optional. org_unit is the id
1092 sub get_org_ancestors {
1093 my( $self, $client, $org_unit, $depth ) = @_;
1094 my $orglist = $apputils->simple_scalar_request(
1096 "open-ils.storage.actor.org_unit.ancestors.atomic",
1097 $org_unit, $depth );
1098 return $U->build_org_tree($orglist);
1102 __PACKAGE__->register_method(
1103 method => "get_standings",
1104 api_name => "open-ils.actor.standings.retrieve"
1109 return $user_standings if $user_standings;
1110 return $user_standings =
1111 $apputils->simple_scalar_request(
1113 "open-ils.cstore.direct.config.standing.search.atomic",
1114 { id => { "!=" => undef } }
1120 __PACKAGE__->register_method(
1121 method => "get_my_org_path",
1122 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1125 sub get_my_org_path {
1126 my( $self, $client, $auth, $org_id ) = @_;
1127 my $e = new_editor(authtoken=>$auth);
1128 return $e->event unless $e->checkauth;
1129 $org_id = $e->requestor->ws_ou unless defined $org_id;
1131 return $apputils->simple_scalar_request(
1133 "open-ils.storage.actor.org_unit.full_path.atomic",
1138 __PACKAGE__->register_method(
1139 method => "patron_adv_search",
1140 api_name => "open-ils.actor.patron.search.advanced" );
1141 sub patron_adv_search {
1142 my( $self, $client, $auth, $search_hash,
1143 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1145 my $e = new_editor(authtoken=>$auth);
1146 return $e->event unless $e->checkauth;
1147 return $e->event unless $e->allowed('VIEW_USER');
1148 return $U->storagereq(
1149 "open-ils.storage.actor.user.crazy_search", $search_hash,
1150 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1154 __PACKAGE__->register_method(
1155 method => "update_passwd",
1157 api_name => "open-ils.actor.user.password.update");
1159 __PACKAGE__->register_method(
1160 method => "update_passwd",
1161 api_name => "open-ils.actor.user.username.update");
1163 __PACKAGE__->register_method(
1164 method => "update_passwd",
1165 api_name => "open-ils.actor.user.email.update");
1168 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1169 my $e = new_editor(xact=>1, authtoken=>$auth);
1170 return $e->die_event unless $e->checkauth;
1172 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1173 or return $e->die_event;
1174 my $api = $self->api_name;
1176 if( $api =~ /password/o ) {
1178 # make sure the original password matches the in-database password
1179 return OpenILS::Event->new('INCORRECT_PASSWORD')
1180 if md5_hex($orig_pw) ne $db_user->passwd;
1181 $db_user->passwd($new_val);
1185 # if we don't clear the password, the user will be updated with
1186 # a hashed version of the hashed version of their password
1187 $db_user->clear_passwd;
1189 if( $api =~ /username/o ) {
1191 # make sure no one else has this username
1192 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1193 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1194 $db_user->usrname($new_val);
1196 } elsif( $api =~ /email/o ) {
1197 $db_user->email($new_val);
1201 $e->update_actor_user($db_user) or return $e->die_event;
1209 __PACKAGE__->register_method(
1210 method => "check_user_perms",
1211 api_name => "open-ils.actor.user.perm.check",
1212 notes => <<" NOTES");
1213 Takes a login session, user id, an org id, and an array of perm type strings. For each
1214 perm type, if the user does *not* have the given permission it is added
1215 to a list which is returned from the method. If all permissions
1216 are allowed, an empty list is returned
1217 if the logged in user does not match 'user_id', then the logged in user must
1218 have VIEW_PERMISSION priveleges.
1221 sub check_user_perms {
1222 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1224 my( $staff, $evt ) = $apputils->checkses($login_session);
1225 return $evt if $evt;
1227 if($staff->id ne $user_id) {
1228 if( $evt = $apputils->check_perms(
1229 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1235 for my $perm (@$perm_types) {
1236 if($apputils->check_perms($user_id, $org_id, $perm)) {
1237 push @not_allowed, $perm;
1241 return \@not_allowed
1244 __PACKAGE__->register_method(
1245 method => "check_user_perms2",
1246 api_name => "open-ils.actor.user.perm.check.multi_org",
1248 Checks the permissions on a list of perms and orgs for a user
1249 @param authtoken The login session key
1250 @param user_id The id of the user to check
1251 @param orgs The array of org ids
1252 @param perms The array of permission names
1253 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1254 if the logged in user does not match 'user_id', then the logged in user must
1255 have VIEW_PERMISSION priveleges.
1258 sub check_user_perms2 {
1259 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1261 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1262 $authtoken, $user_id, 'VIEW_PERMISSION' );
1263 return $evt if $evt;
1266 for my $org (@$orgs) {
1267 for my $perm (@$perms) {
1268 if($apputils->check_perms($user_id, $org, $perm)) {
1269 push @not_allowed, [ $org, $perm ];
1274 return \@not_allowed
1278 __PACKAGE__->register_method(
1279 method => 'check_user_perms3',
1280 api_name => 'open-ils.actor.user.perm.highest_org',
1282 Returns the highest org unit id at which a user has a given permission
1283 If the requestor does not match the target user, the requestor must have
1284 'VIEW_PERMISSION' rights at the home org unit of the target user
1285 @param authtoken The login session key
1286 @param userid The id of the user in question
1287 @param perm The permission to check
1288 @return The org unit highest in the org tree within which the user has
1289 the requested permission
1292 sub check_user_perms3 {
1293 my($self, $client, $authtoken, $user_id, $perm) = @_;
1294 my $e = new_editor(authtoken=>$authtoken);
1295 return $e->event unless $e->checkauth;
1297 my $tree = $U->get_org_tree();
1299 unless($e->requestor->id == $user_id) {
1300 my $user = $e->retrieve_actor_user($user_id)
1301 or return $e->event;
1302 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1303 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1306 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1310 __PACKAGE__->register_method(
1311 method => 'check_user_work_perms',
1312 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1316 Returns a set of org units which represent the highest orgs in
1317 the org tree where the user has the requested permission. The
1318 purpose of this method is to return the smallest set of org units
1319 which represent the full expanse of the user's ability to perform
1320 the requested action. The user whose perms this method should
1321 check is implied by the authtoken. /,
1323 {desc => 'authtoken', type => 'string'},
1324 {desc => 'permission name', type => 'string'},
1325 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1327 return => {desc => 'An array of org IDs'}
1331 __PACKAGE__->register_method(
1332 method => 'check_user_work_perms',
1333 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1336 @see open-ils.actor.user.work_perm.highest_org_set
1337 Returns a list of org trees. The root of each tree
1338 is the highest org in the organization hierarchy where the user has the
1339 requested permission. Below each tree root is its full tree of descendants.
1343 __PACKAGE__->register_method(
1344 method => 'check_user_work_perms',
1345 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1348 @see open-ils.actor.user.work_perm.highest_org_set
1349 Returns a list of list of all of the org_units where the user
1350 has the requested permission. The first item in each list
1351 is the highest permission org for that section of the
1352 org tree. The remaining items in each sub-list are the
1353 descendants of that org.
1358 __PACKAGE__->register_method(
1359 method => 'check_user_work_perms',
1360 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1363 @see open-ils.actor.user.work_perm.highest_org_set
1364 Returns a list of lists of all of the org_unit IDs where the user
1365 has the requested permission. The first item in each list
1366 is the highest permission org for that section of the
1367 org tree. The remaining items in each sub-list are the
1368 descendants of that org.
1372 __PACKAGE__->register_method(
1373 method => 'check_user_work_perms_batch',
1374 api_name => 'open-ils.actor.user.work_perm.highest_org_set.batch',
1377 __PACKAGE__->register_method(
1378 method => 'check_user_work_perms_batch',
1379 api_name => 'open-ils.actor.user.work_perm.org_tree_list.batch',
1382 __PACKAGE__->register_method(
1383 method => 'check_user_work_perms_batch',
1384 api_name => 'open-ils.actor.user.work_perm.org_unit_list.batch',
1387 __PACKAGE__->register_method(
1388 method => 'check_user_work_perms_batch',
1389 api_name => 'open-ils.actor.user.work_perm.org_id_list.batch',
1394 sub check_user_work_perms {
1395 my($self, $conn, $auth, $perm, $options) = @_;
1396 my $e = new_editor(authtoken=>$auth);
1397 return $e->event unless $e->checkauth;
1398 return check_user_work_perms_impl($self, $conn, $e, $perm, $options);
1401 sub check_user_work_perms_batch {
1402 my($self, $conn, $auth, $perm_list, $options) = @_;
1403 my $e = new_editor(authtoken=>$auth);
1404 return $e->event unless $e->checkauth;
1406 $map->{$_} = check_user_work_perms_impl($self, $conn, $e, $_, $options) for @$perm_list;
1410 sub check_user_work_perms_impl {
1411 my($self, $conn, $e, $perm, $options) = @_;
1412 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1414 return $orglist if $self->api_name =~ /highest_org_set/;
1416 # build a list of org trees
1417 return get_org_descendants($self, $conn, $orglist)
1418 if $self->api_name =~ /org_tree_list/;
1421 for my $orgid (@$orglist) {
1422 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1423 unshift @sublist, $orgid; # make sure it's at the front of the list
1424 if($self->api_name =~ /org_id_list/) {
1425 push(@list, @sublist);
1427 push(@list, @{$e->batch_retrieve_actor_org_unit(\@sublist)});
1435 __PACKAGE__->register_method(
1436 method => 'check_user_perms4',
1437 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1439 Returns the highest org unit id at which a user has a given permission
1440 If the requestor does not match the target user, the requestor must have
1441 'VIEW_PERMISSION' rights at the home org unit of the target user
1442 @param authtoken The login session key
1443 @param userid The id of the user in question
1444 @param perms An array of perm names to check
1445 @return An array of orgId's representing the org unit
1446 highest in the org tree within which the user has the requested permission
1447 The arrah of orgId's has matches the order of the perms array
1450 sub check_user_perms4 {
1451 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1453 my( $staff, $target, $org, $evt );
1455 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1456 $authtoken, $userid, 'VIEW_PERMISSION' );
1457 return $evt if $evt;
1460 return [] unless ref($perms);
1461 my $tree = $U->get_org_tree();
1463 for my $p (@$perms) {
1464 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1472 __PACKAGE__->register_method(
1473 method => "user_fines_summary",
1474 api_name => "open-ils.actor.user.fines.summary",
1476 notes => <<" NOTES");
1477 Returns a short summary of the users total open fines, excluding voided fines
1478 Params are login_session, user_id
1479 Returns a 'mous' object.
1482 sub user_fines_summary {
1483 my( $self, $client, $auth, $user_id ) = @_;
1484 my $e = new_editor(authtoken=>$auth);
1485 return $e->event unless $e->checkauth;
1486 my $user = $e->retrieve_actor_user($user_id)
1487 or return $e->event;
1489 if( $user_id ne $e->requestor->id ) {
1490 return $e->event unless
1491 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1494 # run this inside a transaction to prevent replication delay errors
1495 my $ses = $U->start_db_session();
1496 my $s = $ses->request(
1497 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1498 $U->rollback_db_session($ses);
1505 __PACKAGE__->register_method(
1506 method => "user_transactions",
1507 api_name => "open-ils.actor.user.transactions",
1508 notes => <<" NOTES");
1509 Returns a list of open user transactions (mbts objects);
1510 Params are login_session, user_id
1511 Optional third parameter is the transactions type. defaults to all
1514 __PACKAGE__->register_method(
1515 method => "user_transactions",
1516 api_name => "open-ils.actor.user.transactions.have_charge",
1517 notes => <<" NOTES");
1518 Returns a list of all open user transactions (mbts objects) that have an initial charge
1519 Params are login_session, user_id
1520 Optional third parameter is the transactions type. defaults to all
1523 __PACKAGE__->register_method(
1524 method => "user_transactions",
1525 api_name => "open-ils.actor.user.transactions.have_balance",
1526 notes => <<" NOTES");
1527 Returns a list of all open user transactions (mbts objects) that have a balance
1528 Params are login_session, user_id
1529 Optional third parameter is the transactions type. defaults to all
1532 __PACKAGE__->register_method(
1533 method => "user_transactions",
1534 api_name => "open-ils.actor.user.transactions.fleshed",
1535 notes => <<" NOTES");
1536 Returns an object/hash of transaction, circ, title where transaction = an open
1537 user transactions (mbts objects), circ is the attached circluation, and title
1538 is the title the circ points to
1539 Params are login_session, user_id
1540 Optional third parameter is the transactions type. defaults to all
1543 __PACKAGE__->register_method(
1544 method => "user_transactions",
1545 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1546 notes => <<" NOTES");
1547 Returns an object/hash of transaction, circ, title where transaction = an open
1548 user transactions that has an initial charge (mbts objects), circ is the
1549 attached circluation, and title is the title the circ points to
1550 Params are login_session, user_id
1551 Optional third parameter is the transactions type. defaults to all
1554 __PACKAGE__->register_method(
1555 method => "user_transactions",
1556 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1557 notes => <<" NOTES");
1558 Returns an object/hash of transaction, circ, title where transaction = an open
1559 user transaction that has a balance (mbts objects), circ is the attached
1560 circluation, and title is the title the circ points to
1561 Params are login_session, user_id
1562 Optional third parameter is the transaction type. defaults to all
1565 __PACKAGE__->register_method(
1566 method => "user_transactions",
1567 api_name => "open-ils.actor.user.transactions.count",
1568 notes => <<" NOTES");
1569 Returns an object/hash of transaction, circ, title where transaction = an open
1570 user transactions (mbts objects), circ is the attached circluation, and title
1571 is the title the circ points to
1572 Params are login_session, user_id
1573 Optional third parameter is the transactions type. defaults to all
1576 __PACKAGE__->register_method(
1577 method => "user_transactions",
1578 api_name => "open-ils.actor.user.transactions.have_charge.count",
1579 notes => <<" NOTES");
1580 Returns an object/hash of transaction, circ, title where transaction = an open
1581 user transactions that has an initial charge (mbts objects), circ is the
1582 attached circluation, and title is the title the circ points to
1583 Params are login_session, user_id
1584 Optional third parameter is the transactions type. defaults to all
1587 __PACKAGE__->register_method(
1588 method => "user_transactions",
1589 api_name => "open-ils.actor.user.transactions.have_balance.count",
1590 notes => <<" NOTES");
1591 Returns an object/hash of transaction, circ, title where transaction = an open
1592 user transaction that has a balance (mbts objects), circ is the attached
1593 circluation, and title is the title the circ points to
1594 Params are login_session, user_id
1595 Optional third parameter is the transaction type. defaults to all
1598 __PACKAGE__->register_method(
1599 method => "user_transactions",
1600 api_name => "open-ils.actor.user.transactions.have_balance.total",
1601 notes => <<" NOTES");
1602 Returns an object/hash of transaction, circ, title where transaction = an open
1603 user transaction that has a balance (mbts objects), circ is the attached
1604 circluation, and title is the title the circ points to
1605 Params are login_session, user_id
1606 Optional third parameter is the transaction type. defaults to all
1611 sub user_transactions {
1612 my( $self, $client, $login_session, $user_id, $type ) = @_;
1614 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1615 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1616 return $evt if $evt;
1618 my $api = $self->api_name();
1622 if(defined($type)) { @xact = (xact_type => $type);
1624 } else { @xact = (); }
1627 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1628 ->run($login_session => $user_id => $type);
1630 if($api =~ /have_charge/o) {
1632 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1634 } elsif($api =~ /have_balance/o) {
1636 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1639 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1643 if($api =~ /total/o) {
1645 for my $t (@$trans) {
1646 $total += $t->balance_owed;
1649 $logger->debug("Total balance owed by user $user_id: $total");
1653 if($api =~ /count/o) { return scalar @$trans; }
1654 if($api !~ /fleshed/o) { return $trans; }
1657 for my $t (@$trans) {
1659 if( $t->xact_type ne 'circulation' ) {
1660 push @resp, {transaction => $t};
1664 my $circ = $apputils->simple_scalar_request(
1666 "open-ils.cstore.direct.action.circulation.retrieve",
1671 my $title = $apputils->simple_scalar_request(
1673 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1674 $circ->target_copy );
1678 my $u = OpenILS::Utils::ModsParser->new();
1679 $u->start_mods_batch($title->marc());
1680 my $mods = $u->finish_mods_batch();
1681 $mods->doc_id($title->id) if $mods;
1683 push @resp, {transaction => $t, circ => $circ, record => $mods };
1691 __PACKAGE__->register_method(
1692 method => "user_transaction_retrieve",
1693 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1695 notes => <<" NOTES");
1696 Returns a fleshedtransaction record
1698 __PACKAGE__->register_method(
1699 method => "user_transaction_retrieve",
1700 api_name => "open-ils.actor.user.transaction.retrieve",
1702 notes => <<" NOTES");
1703 Returns a transaction record
1705 sub user_transaction_retrieve {
1706 my( $self, $client, $login_session, $bill_id ) = @_;
1708 # XXX I think I'm deprecated... make sure
1710 my $trans = $apputils->simple_scalar_request(
1712 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1716 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1717 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1718 return $evt if $evt;
1720 my $api = $self->api_name();
1721 if($api !~ /fleshed/o) { return $trans; }
1723 if( $trans->xact_type ne 'circulation' ) {
1724 $logger->debug("Returning non-circ transaction");
1725 return {transaction => $trans};
1728 my $circ = $apputils->simple_scalar_request(
1730 "open-ils..direct.action.circulation.retrieve",
1733 return {transaction => $trans} unless $circ;
1734 $logger->debug("Found the circ transaction");
1736 my $title = $apputils->simple_scalar_request(
1738 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1739 $circ->target_copy );
1741 return {transaction => $trans, circ => $circ } unless $title;
1742 $logger->debug("Found the circ title");
1746 my $u = OpenILS::Utils::ModsParser->new();
1747 $u->start_mods_batch($title->marc());
1748 $mods = $u->finish_mods_batch();
1750 if ($title->id == OILS_PRECAT_RECORD) {
1751 my $copy = $apputils->simple_scalar_request(
1753 "open-ils.cstore.direct.asset.copy.retrieve",
1754 $circ->target_copy );
1756 $mods = new Fieldmapper::metabib::virtual_record;
1757 $mods->doc_id(OILS_PRECAT_RECORD);
1758 $mods->title($copy->dummy_title);
1759 $mods->author($copy->dummy_author);
1763 $logger->debug("MODSized the circ title");
1765 return {transaction => $trans, circ => $circ, record => $mods };
1769 __PACKAGE__->register_method(
1770 method => "hold_request_count",
1771 api_name => "open-ils.actor.user.hold_requests.count",
1774 notes => <<" NOTES");
1775 Returns hold ready/total counts
1777 sub hold_request_count {
1778 my( $self, $client, $login_session, $userid ) = @_;
1780 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1781 $login_session, $userid, 'VIEW_HOLD' );
1782 return $evt if $evt;
1785 my $holds = $apputils->simple_scalar_request(
1787 "open-ils.cstore.direct.action.hold_request.search.atomic",
1790 fulfillment_time => {"=" => undef },
1791 cancel_time => undef,
1796 for my $h (@$holds) {
1797 next unless $h->capture_time and $h->current_copy;
1799 my $copy = $apputils->simple_scalar_request(
1801 "open-ils.cstore.direct.asset.copy.retrieve",
1805 if ($copy and $copy->status == 8) {
1810 return { total => scalar(@$holds), ready => scalar(@ready) };
1814 __PACKAGE__->register_method(
1815 method => "checkedout_count",
1816 api_name => "open-ils.actor.user.checked_out.count__",
1818 notes => <<" NOTES");
1819 Returns a transaction record
1823 sub checkedout_count {
1824 my( $self, $client, $login_session, $userid ) = @_;
1826 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1827 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1828 return $evt if $evt;
1830 my $circs = $apputils->simple_scalar_request(
1832 "open-ils.cstore.direct.action.circulation.search.atomic",
1833 { usr => $userid, stop_fines => undef }
1834 #{ usr => $userid, checkin_time => {"=" => undef } }
1837 my $parser = DateTime::Format::ISO8601->new;
1840 for my $c (@$circs) {
1841 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1842 my $due = $due_dt->epoch;
1844 if ($due < DateTime->today->epoch) {
1849 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1853 __PACKAGE__->register_method(
1854 method => "checked_out",
1855 api_name => "open-ils.actor.user.checked_out",
1859 Returns a structure of circulations objects sorted by
1860 out, overdue, lost, claims_returned, long_overdue.
1861 A list of IDs are returned of each type.
1862 lost, long_overdue, and claims_returned circ will not
1863 be "finished" (there is an outstanding balance or some
1864 other pending action on the circ).
1866 The .count method also includes a 'total' field which
1867 sums all "open" circs
1871 __PACKAGE__->register_method(
1872 method => "checked_out",
1873 api_name => "open-ils.actor.user.checked_out.count",
1876 signature => q/@see open-ils.actor.user.checked_out/
1880 my( $self, $conn, $auth, $userid ) = @_;
1882 my $e = new_editor(authtoken=>$auth);
1883 return $e->event unless $e->checkauth;
1885 if( $userid ne $e->requestor->id ) {
1886 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1889 my $count = $self->api_name =~ /count/;
1890 return _checked_out( $count, $e, $userid );
1894 my( $iscount, $e, $userid ) = @_;
1895 my $meth = 'open-ils.storage.actor.user.checked_out';
1896 $meth = "$meth.count" if $iscount;
1897 return $U->storagereq($meth, $userid);
1901 sub _checked_out_WHAT {
1902 my( $iscount, $e, $userid ) = @_;
1904 my $circs = $e->search_action_circulation(
1905 { usr => $userid, stop_fines => undef });
1907 my $mcircs = $e->search_action_circulation(
1910 checkin_time => undef,
1911 xact_finish => undef,
1915 push( @$circs, @$mcircs );
1917 my $parser = DateTime::Format::ISO8601->new;
1919 # split the circs up into overdue and not-overdue circs
1921 for my $c (@$circs) {
1922 if( $c->due_date ) {
1923 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1924 my $due = $due_dt->epoch;
1925 if ($due < DateTime->today->epoch) {
1926 push @overdue, $c->id;
1935 # grab all of the lost, claims-returned, and longoverdue circs
1936 #my $open = $e->search_action_circulation(
1937 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1940 # these items have stop_fines, but no xact_finish, so money
1941 # is owed on them and they have not been checked in
1942 my $open = $e->search_action_circulation(
1945 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1946 xact_finish => undef,
1947 checkin_time => undef,
1952 my( @lost, @cr, @lo );
1953 for my $c (@$open) {
1954 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1955 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1956 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1962 total => @$circs + @lost + @cr + @lo,
1963 out => scalar(@out),
1964 overdue => scalar(@overdue),
1965 lost => scalar(@lost),
1966 claims_returned => scalar(@cr),
1967 long_overdue => scalar(@lo)
1973 overdue => \@overdue,
1975 claims_returned => \@cr,
1976 long_overdue => \@lo
1982 __PACKAGE__->register_method(
1983 method => "checked_in_with_fines",
1984 api_name => "open-ils.actor.user.checked_in_with_fines",
1987 signature => q/@see open-ils.actor.user.checked_out/
1989 sub checked_in_with_fines {
1990 my( $self, $conn, $auth, $userid ) = @_;
1992 my $e = new_editor(authtoken=>$auth);
1993 return $e->event unless $e->checkauth;
1995 if( $userid ne $e->requestor->id ) {
1996 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1999 # money is owed on these items and they are checked in
2000 my $open = $e->search_action_circulation(
2003 xact_finish => undef,
2004 checkin_time => { "!=" => undef },
2009 my( @lost, @cr, @lo );
2010 for my $c (@$open) {
2011 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2012 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2013 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2018 claims_returned => \@cr,
2019 long_overdue => \@lo
2031 __PACKAGE__->register_method(
2032 method => "user_transaction_history",
2033 api_name => "open-ils.actor.user.transactions.history",
2035 notes => <<" NOTES");
2036 Returns a list of billable transaction ids for a user, optionally by type
2038 __PACKAGE__->register_method(
2039 method => "user_transaction_history",
2040 api_name => "open-ils.actor.user.transactions.history.have_charge",
2042 notes => <<" NOTES");
2043 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2045 __PACKAGE__->register_method(
2046 method => "user_transaction_history",
2047 api_name => "open-ils.actor.user.transactions.history.have_balance",
2050 notes => <<" NOTES");
2051 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2053 __PACKAGE__->register_method(
2054 method => "user_transaction_history",
2055 api_name => "open-ils.actor.user.transactions.history.still_open",
2057 notes => <<" NOTES");
2058 Returns a list of billable transaction ids for a user that are not finished
2060 __PACKAGE__->register_method(
2061 method => "user_transaction_history",
2062 api_name => "open-ils.actor.user.transactions.history.have_bill",
2065 notes => <<" NOTES");
2066 Returns a list of billable transaction ids for a user that has billings
2069 sub user_transaction_history {
2070 my( $self, $conn, $auth, $userid, $type ) = @_;
2072 # run inside of a transaction to prevent replication delays
2073 my $e = new_editor(xact=>1, authtoken=>$auth);
2074 return $e->die_event unless $e->checkauth;
2076 if( $e->requestor->id ne $userid ) {
2077 return $e->die_event
2078 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2081 my $api = $self->api_name;
2082 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2084 my @xacts = @{ $e->search_money_billable_transaction(
2085 [ { usr => $userid, @xact_finish },
2087 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2088 order_by => { mbt => 'xact_start DESC' },
2096 #my @mbts = _make_mbts( @xacts );
2097 my @mbts = $U->make_mbts( @xacts );
2099 if(defined($type)) {
2100 @mbts = grep { $_->xact_type eq $type } @mbts;
2103 if($api =~ /have_balance/o) {
2104 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2107 if($api =~ /have_charge/o) {
2108 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2111 if($api =~ /have_bill/o) {
2112 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2120 __PACKAGE__->register_method(
2121 method => "user_perms",
2122 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2124 notes => <<" NOTES");
2125 Returns a list of permissions
2128 my( $self, $client, $authtoken, $user ) = @_;
2130 my( $staff, $evt ) = $apputils->checkses($authtoken);
2131 return $evt if $evt;
2133 $user ||= $staff->id;
2135 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2139 return $apputils->simple_scalar_request(
2141 "open-ils.storage.permission.user_perms.atomic",
2145 __PACKAGE__->register_method(
2146 method => "retrieve_perms",
2147 api_name => "open-ils.actor.permissions.retrieve",
2148 notes => <<" NOTES");
2149 Returns a list of permissions
2151 sub retrieve_perms {
2152 my( $self, $client ) = @_;
2153 return $apputils->simple_scalar_request(
2155 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2156 { id => { '!=' => undef } }
2160 __PACKAGE__->register_method(
2161 method => "retrieve_groups",
2162 api_name => "open-ils.actor.groups.retrieve",
2163 notes => <<" NOTES");
2164 Returns a list of user groupss
2166 sub retrieve_groups {
2167 my( $self, $client ) = @_;
2168 return new_editor()->retrieve_all_permission_grp_tree();
2171 __PACKAGE__->register_method(
2172 method => "retrieve_org_address",
2173 api_name => "open-ils.actor.org_unit.address.retrieve",
2174 notes => <<' NOTES');
2175 Returns an org_unit address by ID
2176 @param An org_address ID
2178 sub retrieve_org_address {
2179 my( $self, $client, $id ) = @_;
2180 return $apputils->simple_scalar_request(
2182 "open-ils.cstore.direct.actor.org_address.retrieve",
2187 __PACKAGE__->register_method(
2188 method => "retrieve_groups_tree",
2189 api_name => "open-ils.actor.groups.tree.retrieve",
2190 notes => <<" NOTES");
2191 Returns a list of user groups
2193 sub retrieve_groups_tree {
2194 my( $self, $client ) = @_;
2195 return new_editor()->search_permission_grp_tree(
2200 flesh_fields => { pgt => ["children"] },
2201 order_by => { pgt => 'name'}
2208 __PACKAGE__->register_method(
2209 method => "add_user_to_groups",
2210 api_name => "open-ils.actor.user.set_groups",
2211 notes => <<" NOTES");
2212 Adds a user to one or more permission groups
2215 sub add_user_to_groups {
2216 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2218 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2219 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2220 return $evt if $evt;
2222 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2223 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2224 return $evt if $evt;
2226 $apputils->simplereq(
2228 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2230 for my $group (@$groups) {
2231 my $link = Fieldmapper::permission::usr_grp_map->new;
2233 $link->usr($userid);
2235 my $id = $apputils->simplereq(
2237 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2243 __PACKAGE__->register_method(
2244 method => "get_user_perm_groups",
2245 api_name => "open-ils.actor.user.get_groups",
2246 notes => <<" NOTES");
2247 Retrieve a user's permission groups.
2251 sub get_user_perm_groups {
2252 my( $self, $client, $authtoken, $userid ) = @_;
2254 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2255 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2256 return $evt if $evt;
2258 return $apputils->simplereq(
2260 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2264 __PACKAGE__->register_method(
2265 method => "get_user_work_ous",
2266 api_name => "open-ils.actor.user.get_work_ous",
2267 notes => <<" NOTES");
2268 Retrieve a user's work org units.
2270 __PACKAGE__->register_method(
2271 method => "get_user_work_ous",
2272 api_name => "open-ils.actor.user.get_work_ous.ids",
2273 notes => <<" NOTES");
2274 Retrieve a user's work org units.
2278 sub get_user_work_ous {
2279 my( $self, $client, $auth, $userid ) = @_;
2280 my $e = new_editor(authtoken=>$auth);
2281 return $e->event unless $e->checkauth;
2282 $userid ||= $e->requestor->id;
2284 if($e->requestor->id != $userid) {
2285 my $user = $e->retrieve_actor_user($userid)
2286 or return $e->event;
2287 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2290 return $e->search_permission_usr_work_ou_map({usr => $userid})
2291 unless $self->api_name =~ /.ids$/;
2293 # client just wants a list of org IDs
2294 return $U->get_user_work_ou_ids($e, $userid);
2300 __PACKAGE__->register_method (
2301 method => 'register_workstation',
2302 api_name => 'open-ils.actor.workstation.register.override',
2303 signature => q/@see open-ils.actor.workstation.register/);
2305 __PACKAGE__->register_method (
2306 method => 'register_workstation',
2307 api_name => 'open-ils.actor.workstation.register',
2309 Registers a new workstion in the system
2310 @param authtoken The login session key
2311 @param name The name of the workstation id
2312 @param owner The org unit that owns this workstation
2313 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2314 if the name is already in use.
2317 sub register_workstation {
2318 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2320 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2321 return $e->die_event unless $e->checkauth;
2322 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2323 my $existing = $e->search_actor_workstation({name => $name})->[0];
2327 if( $self->api_name =~ /override/o ) {
2328 # workstation with the given name exists.
2330 if($owner ne $existing->owning_lib) {
2331 # if necessary, update the owning_lib of the workstation
2333 $logger->info("changing owning lib of workstation ".$existing->id.
2334 " from ".$existing->owning_lib." to $owner");
2335 return $e->die_event unless
2336 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2338 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2340 $existing->owning_lib($owner);
2341 return $e->die_event unless $e->update_actor_workstation($existing);
2347 "attempt to register an existing workstation. returning existing ID");
2350 return $existing->id;
2353 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2357 my $ws = Fieldmapper::actor::workstation->new;
2358 $ws->owning_lib($owner);
2360 $e->create_actor_workstation($ws) or return $e->die_event;
2362 return $ws->id; # note: editor sets the id on the new object for us
2365 __PACKAGE__->register_method (
2366 method => 'workstation_list',
2367 api_name => 'open-ils.actor.workstation.list',
2369 Returns a list of workstations registered at the given location
2370 @param authtoken The login session key
2371 @param ids A list of org_unit.id's for the workstation owners
2374 sub workstation_list {
2375 my( $self, $conn, $authtoken, @orgs ) = @_;
2377 my $e = new_editor(authtoken=>$authtoken);
2378 return $e->event unless $e->checkauth;
2383 unless $e->allowed('REGISTER_WORKSTATION', $o);
2384 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2395 __PACKAGE__->register_method (
2396 method => 'fetch_patron_note',
2397 api_name => 'open-ils.actor.note.retrieve.all',
2400 Returns a list of notes for a given user
2401 Requestor must have VIEW_USER permission if pub==false and
2402 @param authtoken The login session key
2403 @param args Hash of params including
2404 patronid : the patron's id
2405 pub : true if retrieving only public notes
2409 sub fetch_patron_note {
2410 my( $self, $conn, $authtoken, $args ) = @_;
2411 my $patronid = $$args{patronid};
2413 my($reqr, $evt) = $U->checkses($authtoken);
2414 return $evt if $evt;
2417 ($patron, $evt) = $U->fetch_user($patronid);
2418 return $evt if $evt;
2421 if( $patronid ne $reqr->id ) {
2422 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2423 return $evt if $evt;
2425 return $U->cstorereq(
2426 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2427 { usr => $patronid, pub => 't' } );
2430 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2431 return $evt if $evt;
2433 return $U->cstorereq(
2434 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2437 __PACKAGE__->register_method (
2438 method => 'create_user_note',
2439 api_name => 'open-ils.actor.note.create',
2441 Creates a new note for the given user
2442 @param authtoken The login session key
2443 @param note The note object
2446 sub create_user_note {
2447 my( $self, $conn, $authtoken, $note ) = @_;
2448 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2449 return $e->die_event unless $e->checkauth;
2451 my $user = $e->retrieve_actor_user($note->usr)
2452 or return $e->die_event;
2454 return $e->die_event unless
2455 $e->allowed('UPDATE_USER',$user->home_ou);
2457 $note->creator($e->requestor->id);
2458 $e->create_actor_usr_note($note) or return $e->die_event;
2464 __PACKAGE__->register_method (
2465 method => 'delete_user_note',
2466 api_name => 'open-ils.actor.note.delete',
2468 Deletes a note for the given user
2469 @param authtoken The login session key
2470 @param noteid The note id
2473 sub delete_user_note {
2474 my( $self, $conn, $authtoken, $noteid ) = @_;
2476 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2477 return $e->die_event unless $e->checkauth;
2478 my $note = $e->retrieve_actor_usr_note($noteid)
2479 or return $e->die_event;
2480 my $user = $e->retrieve_actor_user($note->usr)
2481 or return $e->die_event;
2482 return $e->die_event unless
2483 $e->allowed('UPDATE_USER', $user->home_ou);
2485 $e->delete_actor_usr_note($note) or return $e->die_event;
2491 __PACKAGE__->register_method (
2492 method => 'update_user_note',
2493 api_name => 'open-ils.actor.note.update',
2495 @param authtoken The login session key
2496 @param note The note
2500 sub update_user_note {
2501 my( $self, $conn, $auth, $note ) = @_;
2502 my $e = new_editor(authtoken=>$auth, xact=>1);
2503 return $e->event unless $e->checkauth;
2504 my $patron = $e->retrieve_actor_user($note->usr)
2505 or return $e->event;
2506 return $e->event unless
2507 $e->allowed('UPDATE_USER', $patron->home_ou);
2508 $e->update_actor_user_note($note)
2509 or return $e->event;
2517 __PACKAGE__->register_method (
2518 method => 'create_closed_date',
2519 api_name => 'open-ils.actor.org_unit.closed_date.create',
2521 Creates a new closing entry for the given org_unit
2522 @param authtoken The login session key
2523 @param note The closed_date object
2526 sub create_closed_date {
2527 my( $self, $conn, $authtoken, $cd ) = @_;
2529 my( $user, $evt ) = $U->checkses($authtoken);
2530 return $evt if $evt;
2532 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2533 return $evt if $evt;
2535 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2537 my $id = $U->storagereq(
2538 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2539 return $U->DB_UPDATE_FAILED($cd) unless $id;
2544 __PACKAGE__->register_method (
2545 method => 'delete_closed_date',
2546 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2548 Deletes a closing entry for the given org_unit
2549 @param authtoken The login session key
2550 @param noteid The close_date id
2553 sub delete_closed_date {
2554 my( $self, $conn, $authtoken, $cd ) = @_;
2556 my( $user, $evt ) = $U->checkses($authtoken);
2557 return $evt if $evt;
2560 ($cd_obj, $evt) = fetch_closed_date($cd);
2561 return $evt if $evt;
2563 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2564 return $evt if $evt;
2566 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2568 my $stat = $U->storagereq(
2569 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2570 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2575 __PACKAGE__->register_method(
2576 method => 'usrname_exists',
2577 api_name => 'open-ils.actor.username.exists',
2579 Returns 1 if the requested username exists, returns 0 otherwise
2583 sub usrname_exists {
2584 my( $self, $conn, $auth, $usrname ) = @_;
2585 my $e = new_editor(authtoken=>$auth);
2586 return $e->event unless $e->checkauth;
2587 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2588 return $$a[0] if $a and @$a;
2592 __PACKAGE__->register_method(
2593 method => 'barcode_exists',
2594 api_name => 'open-ils.actor.barcode.exists',
2597 Returns 1 if the requested barcode exists, returns 0 otherwise
2601 sub barcode_exists {
2602 my( $self, $conn, $auth, $barcode ) = @_;
2603 my $e = new_editor(authtoken=>$auth);
2604 return $e->event unless $e->checkauth;
2605 my $card = $e->search_actor_card({barcode => $barcode});
2611 #return undef unless @$card;
2612 #return $card->[0]->usr;
2616 __PACKAGE__->register_method(
2617 method => 'retrieve_net_levels',
2618 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2621 sub retrieve_net_levels {
2622 my( $self, $conn, $auth ) = @_;
2623 my $e = new_editor(authtoken=>$auth);
2624 return $e->event unless $e->checkauth;
2625 return $e->retrieve_all_config_net_access_level();
2629 __PACKAGE__->register_method(
2630 method => 'fetch_org_by_shortname',
2631 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2633 sub fetch_org_by_shortname {
2634 my( $self, $conn, $sname ) = @_;
2635 my $e = new_editor();
2636 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2637 return $e->event unless $org;
2642 __PACKAGE__->register_method(
2643 method => 'session_home_lib',
2644 api_name => 'open-ils.actor.session.home_lib',
2647 sub session_home_lib {
2648 my( $self, $conn, $auth ) = @_;
2649 my $e = new_editor(authtoken=>$auth);
2650 return undef unless $e->checkauth;
2651 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2652 return $org->shortname;
2655 __PACKAGE__->register_method(
2656 method => 'session_safe_token',
2657 api_name => 'open-ils.actor.session.safe_token',
2659 Returns a hashed session ID that is safe for export to the world.
2660 This safe token will expire after 1 hour of non-use.
2661 @param auth Active authentication token
2665 sub session_safe_token {
2666 my( $self, $conn, $auth ) = @_;
2667 my $e = new_editor(authtoken=>$auth);
2668 return undef unless $e->checkauth;
2670 my $safe_token = md5_hex($auth);
2672 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2674 # Add more like the following if needed...
2676 "safe-token-home_lib-shortname-$safe_token",
2677 $e->retrieve_actor_org_unit(
2678 $e->requestor->home_ou
2687 __PACKAGE__->register_method(
2688 method => 'safe_token_home_lib',
2689 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2691 Returns the home library shortname from the session
2692 asscociated with a safe token from generated by
2693 open-ils.actor.session.safe_token.
2694 @param safe_token Active safe token
2698 sub safe_token_home_lib {
2699 my( $self, $conn, $safe_token ) = @_;
2701 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2702 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2707 __PACKAGE__->register_method(
2708 method => 'slim_tree',
2709 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2712 my $tree = new_editor()->search_actor_org_unit(
2714 {"parent_ou" => undef },
2717 flesh_fields => { aou => ['children'] },
2718 order_by => { aou => 'name'},
2719 select => { aou => ["id","shortname", "name"]},
2724 return trim_tree($tree);
2730 return undef unless $tree;
2732 code => $tree->shortname,
2733 name => $tree->name,
2735 if( $tree->children and @{$tree->children} ) {
2736 $htree->{children} = [];
2737 for my $c (@{$tree->children}) {
2738 push( @{$htree->{children}}, trim_tree($c) );
2746 __PACKAGE__->register_method(
2747 method => "update_penalties",
2748 api_name => "open-ils.actor.user.penalties.update");
2749 sub update_penalties {
2750 my( $self, $conn, $auth, $userid ) = @_;
2751 my $e = new_editor(authtoken=>$auth);
2752 return $e->event unless $e->checkauth;
2753 $U->update_patron_penalties(
2755 patronid => $userid,
2762 __PACKAGE__->register_method(
2763 method => "user_retrieve_fleshed_by_id",
2764 api_name => "open-ils.actor.user.fleshed.retrieve",);
2766 sub user_retrieve_fleshed_by_id {
2767 my( $self, $client, $auth, $user_id, $fields ) = @_;
2768 my $e = new_editor(authtoken => $auth);
2769 return $e->event unless $e->checkauth;
2771 if( $e->requestor->id != $user_id ) {
2772 return $e->event unless $e->allowed('VIEW_USER');
2778 "standing_penalties",
2782 "stat_cat_entries" ];
2783 return new_flesh_user($user_id, $fields, $e);
2787 sub new_flesh_user {
2790 my $fields = shift || [];
2791 my $e = shift || new_editor(xact=>1);
2793 my $user = $e->retrieve_actor_user(
2798 "flesh_fields" => { "au" => $fields }
2801 ) or return $e->event;
2804 if( grep { $_ eq 'addresses' } @$fields ) {
2806 $user->addresses([]) unless @{$user->addresses};
2808 if( ref $user->billing_address ) {
2809 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2810 push( @{$user->addresses}, $user->billing_address );
2814 if( ref $user->mailing_address ) {
2815 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2816 push( @{$user->addresses}, $user->mailing_address );
2822 $user->clear_passwd();
2829 __PACKAGE__->register_method(
2830 method => "user_retrieve_parts",
2831 api_name => "open-ils.actor.user.retrieve.parts",);
2833 sub user_retrieve_parts {
2834 my( $self, $client, $auth, $user_id, $fields ) = @_;
2835 my $e = new_editor(authtoken => $auth);
2836 return $e->event unless $e->checkauth;
2837 if( $e->requestor->id != $user_id ) {
2838 return $e->event unless $e->allowed('VIEW_USER');
2841 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2842 push(@resp, $user->$_()) for(@$fields);
2848 __PACKAGE__->register_method(
2849 method => 'user_opt_in_enabled',
2850 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2852 @return 1 if user opt-in is globally enabled, 0 otherwise.
2855 sub user_opt_in_enabled {
2856 my($self, $conn) = @_;
2857 my $sc = OpenSRF::Utils::SettingsClient->new;
2858 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2863 __PACKAGE__->register_method(
2864 method => 'user_opt_in_at_org',
2865 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2867 @param $auth The auth token
2868 @param user_id The ID of the user to test
2869 @return 1 if the user has opted in at the specified org,
2870 event on error, and 0 otherwise. /);
2871 sub user_opt_in_at_org {
2872 my($self, $conn, $auth, $user_id) = @_;
2874 # see if we even need to enforce the opt-in value
2875 return 1 unless user_opt_in_enabled($self);
2877 my $e = new_editor(authtoken => $auth);
2878 return $e->event unless $e->checkauth;
2879 my $org_id = $e->requestor->ws_ou;
2881 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2882 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2884 # user is automatically opted-in at the home org
2885 return 1 if $user->home_ou eq $org_id;
2887 my $vals = $e->search_actor_usr_org_unit_opt_in(
2888 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2894 __PACKAGE__->register_method(
2895 method => 'create_user_opt_in_at_org',
2896 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2898 @param $auth The auth token
2899 @param user_id The ID of the user to test
2900 @return The ID of the newly created object, event on error./);
2902 sub create_user_opt_in_at_org {
2903 my($self, $conn, $auth, $user_id) = @_;
2905 my $e = new_editor(authtoken => $auth, xact=>1);
2906 return $e->die_event unless $e->checkauth;
2907 my $org_id = $e->requestor->ws_ou;
2909 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2910 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2912 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2914 $opt_in->org_unit($org_id);
2915 $opt_in->usr($user_id);
2916 $opt_in->staff($e->requestor->id);
2917 $opt_in->opt_in_ts('now');
2918 $opt_in->opt_in_ws($e->requestor->wsid);
2920 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2921 or return $e->die_event;
2929 __PACKAGE__->register_method (
2930 method => 'retrieve_org_hours',
2931 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
2933 Returns the hours of operation for a specified org unit
2934 @param authtoken The login session key
2935 @param org_id The org_unit ID
2939 sub retrieve_org_hours {
2940 my($self, $conn, $auth, $org_id) = @_;
2941 my $e = new_editor(authtoken => $auth);
2942 return $e->die_event unless $e->checkauth;
2943 $org_id ||= $e->requestor->ws_ou;
2944 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);