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;
31 use OpenILS::Application::Actor::UserGroups;
32 use OpenILS::Application::Actor::Friends;
34 use OpenILS::Utils::CStoreEditor qw/:funcs/;
35 use OpenILS::Utils::Penalty;
38 OpenILS::Application::Actor::Container->initialize();
39 OpenILS::Application::Actor::UserGroups->initialize();
40 OpenILS::Application::Actor::ClosedDates->initialize();
43 my $apputils = "OpenILS::Application::AppUtils";
46 sub _d { warn "Patron:\n" . Dumper(shift()); }
49 my $set_user_settings;
53 __PACKAGE__->register_method(
54 method => "update_user_setting",
55 api_name => "open-ils.actor.patron.settings.update",
57 sub update_user_setting {
58 my($self, $conn, $auth, $user_id, $settings) = @_;
59 my $e = new_editor(xact => 1, authtoken => $auth);
60 return $e->die_event unless $e->checkauth;
62 $user_id = $e->requestor->id unless defined $user_id;
64 unless($e->requestor->id == $user_id) {
65 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
66 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
69 for my $name (keys %$settings) {
70 my $val = $$settings{$name};
71 my $set = $e->search_actor_user_setting({usr => $user_id, name => $name})->[0];
74 $val = OpenSRF::Utils::JSON->perl2JSON($val);
77 $e->update_actor_user_setting($set) or return $e->die_event;
79 $set = Fieldmapper::actor::user_setting->new;
83 $e->create_actor_user_setting($set) or return $e->die_event;
86 $e->delete_actor_user_setting($set) or return $e->die_event;
95 __PACKAGE__->register_method(
96 method => "set_ou_settings",
97 api_name => "open-ils.actor.org_unit.settings.update",
100 my( $self, $client, $auth, $org_id, $settings ) = @_;
102 my $e = new_editor(authtoken => $auth, xact => 1);
103 return $e->die_event unless $e->checkauth;
105 for my $name (keys %$settings) {
106 my $val = $$settings{$name};
107 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
109 return $e->die_event unless $e->allowed("UPDATE_ORG_UNIT_SETTING.$name", $org_id);
112 $val = OpenSRF::Utils::JSON->perl2JSON($val);
115 $e->update_actor_org_unit_setting($set) or return $e->die_event;
117 $set = Fieldmapper::actor::org_unit_setting->new;
118 $set->org_unit($org_id);
121 $e->create_actor_org_unit_setting($set) or return $e->die_event;
124 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
132 my $fetch_user_settings;
133 my $fetch_ou_settings;
135 __PACKAGE__->register_method(
136 method => "user_settings",
137 api_name => "open-ils.actor.patron.settings.retrieve",
140 my( $self, $client, $auth, $user_id, $setting ) = @_;
142 my $e = new_editor(authtoken => $auth);
143 return $e->event unless $e->checkauth;
144 $user_id = $e->requestor->id unless defined $user_id;
146 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
147 if($e->requestor->id != $user_id) {
148 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
152 my $val = $e->search_actor_user_setting({usr => $user_id, name => $setting})->[0];
153 return '' unless $val;
154 return OpenSRF::Utils::JSON->JSON2perl($val->value);
156 my $s = $e->search_actor_user_setting({usr => $user_id});
157 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
163 __PACKAGE__->register_method(
164 method => "ou_settings",
165 api_name => "open-ils.actor.org_unit.settings.retrieve",
168 my( $self, $client, $ouid ) = @_;
170 $logger->info("Fetching org unit settings for org $ouid");
172 my $s = $apputils->simplereq(
174 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
176 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
181 __PACKAGE__->register_method(
182 api_name => 'open-ils.actor.ou_setting.ancestor_default',
183 method => 'ou_ancestor_setting',
186 # ------------------------------------------------------------------
187 # Attempts to find the org setting value for a given org. if not
188 # found at the requested org, searches up the org tree until it
189 # finds a parent that has the requested setting.
190 # when found, returns { org => $id, value => $value }
191 # otherwise, returns NULL
192 # ------------------------------------------------------------------
193 sub ou_ancestor_setting {
194 my( $self, $client, $orgid, $name ) = @_;
195 return $U->ou_ancestor_setting($orgid, $name);
198 __PACKAGE__->register_method(
199 api_name => 'open-ils.actor.ou_setting.ancestor_default.batch',
200 method => 'ou_ancestor_setting_batch',
202 sub ou_ancestor_setting_batch {
203 my( $self, $client, $orgid, $name_list ) = @_;
205 $values{$_} = $U->ou_ancestor_setting($orgid, $_) for @$name_list;
212 __PACKAGE__->register_method (
213 method => "ou_setting_delete",
214 api_name => 'open-ils.actor.org_setting.delete',
216 Deletes a specific org unit setting for a specific location
217 @param authtoken The login session key
218 @param orgid The org unit whose setting we're changing
219 @param setting The name of the setting to delete
220 @return True value on success.
224 sub ou_setting_delete {
225 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
226 my( $reqr, $evt) = $U->checkses($authtoken);
228 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
231 my $id = $U->cstorereq(
232 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
233 { name => $setting, org_unit => $orgid } );
235 $logger->debug("Retrieved setting $id in org unit setting delete");
237 my $s = $U->cstorereq(
238 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
240 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
254 __PACKAGE__->register_method(
255 method => "update_patron",
256 api_name => "open-ils.actor.patron.update",);
259 my( $self, $client, $user_session, $patron ) = @_;
261 my $session = $apputils->start_db_session();
265 $logger->info("Creating new patron...") if $patron->isnew;
266 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
268 my( $user_obj, $evt ) = $U->checkses($user_session);
271 $evt = check_group_perm($session, $user_obj, $patron);
275 # $new_patron is the patron in progress. $patron is the original patron
276 # passed in with the method. new_patron will change as the components
277 # of patron are added/updated.
281 # unflesh the real items on the patron
282 $patron->card( $patron->card->id ) if(ref($patron->card));
283 $patron->billing_address( $patron->billing_address->id )
284 if(ref($patron->billing_address));
285 $patron->mailing_address( $patron->mailing_address->id )
286 if(ref($patron->mailing_address));
288 # create/update the patron first so we can use his id
289 if($patron->isnew()) {
290 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
292 } else { $new_patron = $patron; }
294 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
297 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
300 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
303 # re-update the patron if anything has happened to him during this process
304 if($new_patron->ischanged()) {
305 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
309 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
312 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
315 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
318 if(!$patron->isnew) {
319 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
322 $apputils->commit_db_session($session);
324 return flesh_user($new_patron->id(), new_editor(requestor => $user_obj));
331 return new_flesh_user($id, [
334 "standing_penalties",
338 "stat_cat_entries" ], $e );
346 # clone and clear stuff that would break the database
350 my $new_patron = $patron->clone;
352 $new_patron->clear_billing_address();
353 $new_patron->clear_mailing_address();
354 $new_patron->clear_addresses();
355 $new_patron->clear_card();
356 $new_patron->clear_cards();
357 $new_patron->clear_id();
358 $new_patron->clear_isnew();
359 $new_patron->clear_ischanged();
360 $new_patron->clear_isdeleted();
361 $new_patron->clear_stat_cat_entries();
362 $new_patron->clear_permissions();
363 $new_patron->clear_standing_penalties();
373 my $user_obj = shift;
375 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
376 return (undef, $evt) if $evt;
378 my $ex = $session->request(
379 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
381 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
384 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
386 my $id = $session->request(
387 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
388 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
390 $logger->info("Successfully created new user [$id] in DB");
392 return ( $session->request(
393 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
397 sub check_group_perm {
398 my( $session, $requestor, $patron ) = @_;
401 # first let's see if the requestor has
402 # priveleges to update this user in any way
403 if( ! $patron->isnew ) {
404 my $p = $session->request(
405 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
407 # If we are the requestor (trying to update our own account)
408 # and we are not trying to change our profile, we're good
409 if( $p->id == $requestor->id and
410 $p->profile == $patron->profile ) {
415 $evt = group_perm_failed($session, $requestor, $p);
419 # They are allowed to edit this patron.. can they put the
420 # patron into the group requested?
421 $evt = group_perm_failed($session, $requestor, $patron);
427 sub group_perm_failed {
428 my( $session, $requestor, $patron ) = @_;
432 my $grpid = $patron->profile;
436 $logger->debug("user update looking for group perm for group $grpid");
437 $grp = $session->request(
438 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
439 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
441 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
443 $logger->info("user update checking perm $perm on user ".
444 $requestor->id." for update/create on user username=".$patron->usrname);
446 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
454 my( $session, $patron, $user_obj, $noperm) = @_;
456 $logger->info("Updating patron ".$patron->id." in DB");
461 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
462 return (undef, $evt) if $evt;
465 # update the password by itself to avoid the password protection magic
466 if( $patron->passwd ) {
467 my $s = $session->request(
468 'open-ils.storage.direct.actor.user.remote_update',
469 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
470 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
471 $patron->clear_passwd;
474 if(!$patron->ident_type) {
475 $patron->clear_ident_type;
476 $patron->clear_ident_value;
479 $evt = verify_last_xact($session, $patron);
480 return (undef, $evt) if $evt;
482 my $stat = $session->request(
483 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
484 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
489 sub verify_last_xact {
490 my( $session, $patron ) = @_;
491 return undef unless $patron->id and $patron->id > 0;
492 my $p = $session->request(
493 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
494 my $xact = $p->last_xact_id;
495 return undef unless $xact;
496 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
497 return OpenILS::Event->new('XACT_COLLISION')
498 if $xact != $patron->last_xact_id;
503 sub _check_dup_ident {
504 my( $session, $patron ) = @_;
506 return undef unless $patron->ident_value;
509 ident_type => $patron->ident_type,
510 ident_value => $patron->ident_value,
513 $logger->debug("patron update searching for dup ident values: " .
514 $patron->ident_type . ':' . $patron->ident_value);
516 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
518 my $dups = $session->request(
519 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
522 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
529 sub _add_update_addresses {
533 my $new_patron = shift;
537 my $current_id; # id of the address before creation
539 for my $address (@{$patron->addresses()}) {
541 next unless ref $address;
542 $current_id = $address->id();
544 if( $patron->billing_address() and
545 $patron->billing_address() == $current_id ) {
546 $logger->info("setting billing addr to $current_id");
547 $new_patron->billing_address($address->id());
548 $new_patron->ischanged(1);
551 if( $patron->mailing_address() and
552 $patron->mailing_address() == $current_id ) {
553 $new_patron->mailing_address($address->id());
554 $logger->info("setting mailing addr to $current_id");
555 $new_patron->ischanged(1);
559 if($address->isnew()) {
561 $address->usr($new_patron->id());
563 ($address, $evt) = _add_address($session,$address);
564 return (undef, $evt) if $evt;
566 # we need to get the new id
567 if( $patron->billing_address() and
568 $patron->billing_address() == $current_id ) {
569 $new_patron->billing_address($address->id());
570 $logger->info("setting billing addr to $current_id");
571 $new_patron->ischanged(1);
574 if( $patron->mailing_address() and
575 $patron->mailing_address() == $current_id ) {
576 $new_patron->mailing_address($address->id());
577 $logger->info("setting mailing addr to $current_id");
578 $new_patron->ischanged(1);
581 } elsif($address->ischanged() ) {
583 ($address, $evt) = _update_address($session, $address);
584 return (undef, $evt) if $evt;
586 } elsif($address->isdeleted() ) {
588 if( $address->id() == $new_patron->mailing_address() ) {
589 $new_patron->clear_mailing_address();
590 ($new_patron, $evt) = _update_patron($session, $new_patron);
591 return (undef, $evt) if $evt;
594 if( $address->id() == $new_patron->billing_address() ) {
595 $new_patron->clear_billing_address();
596 ($new_patron, $evt) = _update_patron($session, $new_patron);
597 return (undef, $evt) if $evt;
600 $evt = _delete_address($session, $address);
601 return (undef, $evt) if $evt;
605 return ( $new_patron, undef );
609 # adds an address to the db and returns the address with new id
611 my($session, $address) = @_;
612 $address->clear_id();
614 $logger->info("Creating new address at street ".$address->street1);
616 # put the address into the database
617 my $id = $session->request(
618 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
619 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
622 return ($address, undef);
626 sub _update_address {
627 my( $session, $address ) = @_;
629 $logger->info("Updating address ".$address->id." in the DB");
631 my $stat = $session->request(
632 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
634 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
635 return ($address, undef);
640 sub _add_update_cards {
644 my $new_patron = shift;
648 my $virtual_id; #id of the card before creation
649 for my $card (@{$patron->cards()}) {
651 $card->usr($new_patron->id());
653 if(ref($card) and $card->isnew()) {
655 $virtual_id = $card->id();
656 ( $card, $evt ) = _add_card($session,$card);
657 return (undef, $evt) if $evt;
659 #if(ref($patron->card)) { $patron->card($patron->card->id); }
660 if($patron->card() == $virtual_id) {
661 $new_patron->card($card->id());
662 $new_patron->ischanged(1);
665 } elsif( ref($card) and $card->ischanged() ) {
666 $evt = _update_card($session, $card);
667 return (undef, $evt) if $evt;
671 return ( $new_patron, undef );
675 # adds an card to the db and returns the card with new id
677 my( $session, $card ) = @_;
680 $logger->info("Adding new patron card ".$card->barcode);
682 my $id = $session->request(
683 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
684 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
685 $logger->info("Successfully created patron card $id");
688 return ( $card, undef );
692 # returns event on error. returns undef otherwise
694 my( $session, $card ) = @_;
695 $logger->info("Updating patron card ".$card->id);
697 my $stat = $session->request(
698 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
699 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
706 # returns event on error. returns undef otherwise
707 sub _delete_address {
708 my( $session, $address ) = @_;
710 $logger->info("Deleting address ".$address->id." from DB");
712 my $stat = $session->request(
713 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
715 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
721 sub _add_survey_responses {
722 my ($session, $patron, $new_patron) = @_;
724 $logger->info( "Updating survey responses for patron ".$new_patron->id );
726 my $responses = $patron->survey_responses;
730 $_->usr($new_patron->id) for (@$responses);
732 my $evt = $U->simplereq( "open-ils.circ",
733 "open-ils.circ.survey.submit.user_id", $responses );
735 return (undef, $evt) if defined($U->event_code($evt));
739 return ( $new_patron, undef );
743 sub _create_stat_maps {
745 my($session, $user_session, $patron, $new_patron) = @_;
747 my $maps = $patron->stat_cat_entries();
749 for my $map (@$maps) {
751 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
753 if ($map->isdeleted()) {
754 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
756 } elsif ($map->isnew()) {
757 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
762 $map->target_usr($new_patron->id);
765 $logger->info("Updating stat entry with method $method and map $map");
767 my $stat = $session->request($method, $map)->gather(1);
768 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
772 return ($new_patron, undef);
775 sub _create_perm_maps {
777 my($session, $user_session, $patron, $new_patron) = @_;
779 my $maps = $patron->permissions;
781 for my $map (@$maps) {
783 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
784 if ($map->isdeleted()) {
785 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
786 } elsif ($map->isnew()) {
787 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
792 $map->usr($new_patron->id);
794 #warn( "Updating permissions with method $method and session $user_session and map $map" );
795 $logger->info( "Updating permissions with method $method and map $map" );
797 my $stat = $session->request($method, $map)->gather(1);
798 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
802 return ($new_patron, undef);
806 __PACKAGE__->register_method(
807 method => "set_user_work_ous",
808 api_name => "open-ils.actor.user.work_ous.update",
811 sub set_user_work_ous {
817 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
820 my $session = $apputils->start_db_session();
822 for my $map (@$maps) {
824 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
825 if ($map->isdeleted()) {
826 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
827 } elsif ($map->isnew()) {
828 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
832 #warn( "Updating permissions with method $method and session $ses and map $map" );
833 $logger->info( "Updating work_ou map with method $method and map $map" );
835 my $stat = $session->request($method, $map)->gather(1);
836 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
840 $apputils->commit_db_session($session);
842 return scalar(@$maps);
846 __PACKAGE__->register_method(
847 method => "set_user_perms",
848 api_name => "open-ils.actor.user.permissions.update",
857 my $session = $apputils->start_db_session();
859 my( $user_obj, $evt ) = $U->checkses($ses);
862 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
865 $all = 1 if ($U->is_true($user_obj->super_user()));
866 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
868 for my $map (@$maps) {
870 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
871 if ($map->isdeleted()) {
872 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
873 } elsif ($map->isnew()) {
874 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
878 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
879 #warn( "Updating permissions with method $method and session $ses and map $map" );
880 $logger->info( "Updating permissions with method $method and map $map" );
882 my $stat = $session->request($method, $map)->gather(1);
883 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
887 $apputils->commit_db_session($session);
889 return scalar(@$maps);
893 __PACKAGE__->register_method(
894 method => "user_retrieve_by_barcode",
896 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
898 sub user_retrieve_by_barcode {
899 my($self, $client, $user_session, $barcode) = @_;
901 $logger->debug("Searching for user with barcode $barcode");
902 my ($user_obj, $evt) = $apputils->checkses($user_session);
905 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
907 "open-ils.cstore.direct.actor.card.search.atomic",
908 { barcode => $barcode }
911 if(!$card || !$card->[0]) {
912 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
916 my $user = flesh_user($card->usr(), new_editor(requestor => $user_obj));
918 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
921 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
928 __PACKAGE__->register_method(
929 method => "get_user_by_id",
931 api_name => "open-ils.actor.user.retrieve",);
934 my ($self, $client, $auth, $id) = @_;
935 my $e = new_editor(authtoken=>$auth);
936 return $e->event unless $e->checkauth;
937 my $user = $e->retrieve_actor_user($id)
939 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
945 __PACKAGE__->register_method(
946 method => "get_org_types",
947 api_name => "open-ils.actor.org_types.retrieve",);
950 return $U->get_org_types();
955 __PACKAGE__->register_method(
956 method => "get_user_ident_types",
957 api_name => "open-ils.actor.user.ident_types.retrieve",
960 sub get_user_ident_types {
961 return $ident_types if $ident_types;
962 return $ident_types =
963 new_editor()->retrieve_all_config_identification_type();
969 __PACKAGE__->register_method(
970 method => "get_org_unit",
971 api_name => "open-ils.actor.org_unit.retrieve",
975 my( $self, $client, $user_session, $org_id ) = @_;
976 my $e = new_editor(authtoken => $user_session);
978 return $e->event unless $e->checkauth;
979 $org_id = $e->requestor->ws_ou;
981 my $o = $e->retrieve_actor_org_unit($org_id)
986 __PACKAGE__->register_method(
987 method => "search_org_unit",
988 api_name => "open-ils.actor.org_unit_list.search",
991 sub search_org_unit {
993 my( $self, $client, $field, $value ) = @_;
995 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
997 "open-ils.cstore.direct.actor.org_unit.search.atomic",
998 { $field => $value } );
1004 # build the org tree
1006 __PACKAGE__->register_method(
1007 method => "get_org_tree",
1008 api_name => "open-ils.actor.org_tree.retrieve",
1010 note => "Returns the entire org tree structure",
1016 return $U->get_org_tree($client->session->session_locale);
1020 __PACKAGE__->register_method(
1021 method => "get_org_descendants",
1022 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1025 # depth is optional. org_unit is the id
1026 sub get_org_descendants {
1027 my( $self, $client, $org_unit, $depth ) = @_;
1029 if(ref $org_unit eq 'ARRAY') {
1032 for my $i (0..scalar(@$org_unit)-1) {
1033 my $list = $U->simple_scalar_request(
1035 "open-ils.storage.actor.org_unit.descendants.atomic",
1036 $org_unit->[$i], $depth->[$i] );
1037 push(@trees, $U->build_org_tree($list));
1042 my $orglist = $apputils->simple_scalar_request(
1044 "open-ils.storage.actor.org_unit.descendants.atomic",
1045 $org_unit, $depth );
1046 return $U->build_org_tree($orglist);
1051 __PACKAGE__->register_method(
1052 method => "get_org_ancestors",
1053 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1056 # depth is optional. org_unit is the id
1057 sub get_org_ancestors {
1058 my( $self, $client, $org_unit, $depth ) = @_;
1059 my $orglist = $apputils->simple_scalar_request(
1061 "open-ils.storage.actor.org_unit.ancestors.atomic",
1062 $org_unit, $depth );
1063 return $U->build_org_tree($orglist);
1067 __PACKAGE__->register_method(
1068 method => "get_standings",
1069 api_name => "open-ils.actor.standings.retrieve"
1074 return $user_standings if $user_standings;
1075 return $user_standings =
1076 $apputils->simple_scalar_request(
1078 "open-ils.cstore.direct.config.standing.search.atomic",
1079 { id => { "!=" => undef } }
1085 __PACKAGE__->register_method(
1086 method => "get_my_org_path",
1087 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1090 sub get_my_org_path {
1091 my( $self, $client, $auth, $org_id ) = @_;
1092 my $e = new_editor(authtoken=>$auth);
1093 return $e->event unless $e->checkauth;
1094 $org_id = $e->requestor->ws_ou unless defined $org_id;
1096 return $apputils->simple_scalar_request(
1098 "open-ils.storage.actor.org_unit.full_path.atomic",
1103 __PACKAGE__->register_method(
1104 method => "patron_adv_search",
1105 api_name => "open-ils.actor.patron.search.advanced" );
1106 sub patron_adv_search {
1107 my( $self, $client, $auth, $search_hash,
1108 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1110 my $e = new_editor(authtoken=>$auth);
1111 return $e->event unless $e->checkauth;
1112 return $e->event unless $e->allowed('VIEW_USER');
1113 return $U->storagereq(
1114 "open-ils.storage.actor.user.crazy_search", $search_hash,
1115 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1119 __PACKAGE__->register_method(
1120 method => "update_passwd",
1122 api_name => "open-ils.actor.user.password.update");
1124 __PACKAGE__->register_method(
1125 method => "update_passwd",
1126 api_name => "open-ils.actor.user.username.update");
1128 __PACKAGE__->register_method(
1129 method => "update_passwd",
1130 api_name => "open-ils.actor.user.email.update");
1133 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1134 my $e = new_editor(xact=>1, authtoken=>$auth);
1135 return $e->die_event unless $e->checkauth;
1137 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1138 or return $e->die_event;
1139 my $api = $self->api_name;
1141 if( $api =~ /password/o ) {
1143 # make sure the original password matches the in-database password
1144 return OpenILS::Event->new('INCORRECT_PASSWORD')
1145 if md5_hex($orig_pw) ne $db_user->passwd;
1146 $db_user->passwd($new_val);
1150 # if we don't clear the password, the user will be updated with
1151 # a hashed version of the hashed version of their password
1152 $db_user->clear_passwd;
1154 if( $api =~ /username/o ) {
1156 # make sure no one else has this username
1157 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1158 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1159 $db_user->usrname($new_val);
1161 } elsif( $api =~ /email/o ) {
1162 $db_user->email($new_val);
1166 $e->update_actor_user($db_user) or return $e->die_event;
1174 __PACKAGE__->register_method(
1175 method => "check_user_perms",
1176 api_name => "open-ils.actor.user.perm.check",
1177 notes => <<" NOTES");
1178 Takes a login session, user id, an org id, and an array of perm type strings. For each
1179 perm type, if the user does *not* have the given permission it is added
1180 to a list which is returned from the method. If all permissions
1181 are allowed, an empty list is returned
1182 if the logged in user does not match 'user_id', then the logged in user must
1183 have VIEW_PERMISSION priveleges.
1186 sub check_user_perms {
1187 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1189 my( $staff, $evt ) = $apputils->checkses($login_session);
1190 return $evt if $evt;
1192 if($staff->id ne $user_id) {
1193 if( $evt = $apputils->check_perms(
1194 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1200 for my $perm (@$perm_types) {
1201 if($apputils->check_perms($user_id, $org_id, $perm)) {
1202 push @not_allowed, $perm;
1206 return \@not_allowed
1209 __PACKAGE__->register_method(
1210 method => "check_user_perms2",
1211 api_name => "open-ils.actor.user.perm.check.multi_org",
1213 Checks the permissions on a list of perms and orgs for a user
1214 @param authtoken The login session key
1215 @param user_id The id of the user to check
1216 @param orgs The array of org ids
1217 @param perms The array of permission names
1218 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1219 if the logged in user does not match 'user_id', then the logged in user must
1220 have VIEW_PERMISSION priveleges.
1223 sub check_user_perms2 {
1224 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1226 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1227 $authtoken, $user_id, 'VIEW_PERMISSION' );
1228 return $evt if $evt;
1231 for my $org (@$orgs) {
1232 for my $perm (@$perms) {
1233 if($apputils->check_perms($user_id, $org, $perm)) {
1234 push @not_allowed, [ $org, $perm ];
1239 return \@not_allowed
1243 __PACKAGE__->register_method(
1244 method => 'check_user_perms3',
1245 api_name => 'open-ils.actor.user.perm.highest_org',
1247 Returns the highest org unit id at which a user has a given permission
1248 If the requestor does not match the target user, the requestor must have
1249 'VIEW_PERMISSION' rights at the home org unit of the target user
1250 @param authtoken The login session key
1251 @param userid The id of the user in question
1252 @param perm The permission to check
1253 @return The org unit highest in the org tree within which the user has
1254 the requested permission
1257 sub check_user_perms3 {
1258 my($self, $client, $authtoken, $user_id, $perm) = @_;
1259 my $e = new_editor(authtoken=>$authtoken);
1260 return $e->event unless $e->checkauth;
1262 my $tree = $U->get_org_tree();
1264 unless($e->requestor->id == $user_id) {
1265 my $user = $e->retrieve_actor_user($user_id)
1266 or return $e->event;
1267 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1268 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1271 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1275 __PACKAGE__->register_method(
1276 method => 'check_user_work_perms',
1277 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1281 Returns a set of org units which represent the highest orgs in
1282 the org tree where the user has the requested permission. The
1283 purpose of this method is to return the smallest set of org units
1284 which represent the full expanse of the user's ability to perform
1285 the requested action. The user whose perms this method should
1286 check is implied by the authtoken. /,
1288 {desc => 'authtoken', type => 'string'},
1289 {desc => 'permission name', type => 'string'},
1290 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1292 return => {desc => 'An array of org IDs'}
1296 __PACKAGE__->register_method(
1297 method => 'check_user_work_perms',
1298 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1301 @see open-ils.actor.user.work_perm.highest_org_set
1302 Returns a list of org trees. The root of each tree
1303 is the highest org in the organization hierarchy where the user has the
1304 requested permission. Below each tree root is its full tree of descendants.
1308 __PACKAGE__->register_method(
1309 method => 'check_user_work_perms',
1310 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1313 @see open-ils.actor.user.work_perm.highest_org_set
1314 Returns a list of list of all of the org_units where the user
1315 has the requested permission. The first item in each list
1316 is the highest permission org for that section of the
1317 org tree. The remaining items in each sub-list are the
1318 descendants of that org.
1323 __PACKAGE__->register_method(
1324 method => 'check_user_work_perms',
1325 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1328 @see open-ils.actor.user.work_perm.highest_org_set
1329 Returns a list of lists of all of the org_unit IDs where the user
1330 has the requested permission. The first item in each list
1331 is the highest permission org for that section of the
1332 org tree. The remaining items in each sub-list are the
1333 descendants of that org.
1337 __PACKAGE__->register_method(
1338 method => 'check_user_work_perms_batch',
1339 api_name => 'open-ils.actor.user.work_perm.highest_org_set.batch',
1342 __PACKAGE__->register_method(
1343 method => 'check_user_work_perms_batch',
1344 api_name => 'open-ils.actor.user.work_perm.org_tree_list.batch',
1347 __PACKAGE__->register_method(
1348 method => 'check_user_work_perms_batch',
1349 api_name => 'open-ils.actor.user.work_perm.org_unit_list.batch',
1352 __PACKAGE__->register_method(
1353 method => 'check_user_work_perms_batch',
1354 api_name => 'open-ils.actor.user.work_perm.org_id_list.batch',
1359 sub check_user_work_perms {
1360 my($self, $conn, $auth, $perm, $options) = @_;
1361 my $e = new_editor(authtoken=>$auth);
1362 return $e->event unless $e->checkauth;
1363 return check_user_work_perms_impl($self, $conn, $e, $perm, $options);
1366 sub check_user_work_perms_batch {
1367 my($self, $conn, $auth, $perm_list, $options) = @_;
1368 my $e = new_editor(authtoken=>$auth);
1369 return $e->event unless $e->checkauth;
1371 $map->{$_} = check_user_work_perms_impl($self, $conn, $e, $_, $options) for @$perm_list;
1375 sub check_user_work_perms_impl {
1376 my($self, $conn, $e, $perm, $options) = @_;
1377 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1379 return $orglist if $self->api_name =~ /highest_org_set/;
1381 # build a list of org trees
1382 return get_org_descendants($self, $conn, $orglist)
1383 if $self->api_name =~ /org_tree_list/;
1386 for my $orgid (@$orglist) {
1387 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1388 unshift @sublist, $orgid; # make sure it's at the front of the list
1389 if($self->api_name =~ /org_id_list/) {
1390 push(@list, @sublist);
1392 push(@list, @{$e->batch_retrieve_actor_org_unit(\@sublist)});
1400 __PACKAGE__->register_method(
1401 method => 'check_user_perms4',
1402 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1404 Returns the highest org unit id at which a user has a given permission
1405 If the requestor does not match the target user, the requestor must have
1406 'VIEW_PERMISSION' rights at the home org unit of the target user
1407 @param authtoken The login session key
1408 @param userid The id of the user in question
1409 @param perms An array of perm names to check
1410 @return An array of orgId's representing the org unit
1411 highest in the org tree within which the user has the requested permission
1412 The arrah of orgId's has matches the order of the perms array
1415 sub check_user_perms4 {
1416 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1418 my( $staff, $target, $org, $evt );
1420 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1421 $authtoken, $userid, 'VIEW_PERMISSION' );
1422 return $evt if $evt;
1425 return [] unless ref($perms);
1426 my $tree = $U->get_org_tree();
1428 for my $p (@$perms) {
1429 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1437 __PACKAGE__->register_method(
1438 method => "user_fines_summary",
1439 api_name => "open-ils.actor.user.fines.summary",
1441 notes => <<" NOTES");
1442 Returns a short summary of the users total open fines, excluding voided fines
1443 Params are login_session, user_id
1444 Returns a 'mous' object.
1447 sub user_fines_summary {
1448 my( $self, $client, $auth, $user_id ) = @_;
1449 my $e = new_editor(authtoken=>$auth);
1450 return $e->event unless $e->checkauth;
1451 my $user = $e->retrieve_actor_user($user_id)
1452 or return $e->event;
1454 if( $user_id ne $e->requestor->id ) {
1455 return $e->event unless
1456 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1459 # run this inside a transaction to prevent replication delay errors
1460 my $ses = $U->start_db_session();
1461 my $s = $ses->request(
1462 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1463 $U->rollback_db_session($ses);
1470 __PACKAGE__->register_method(
1471 method => "user_transactions",
1472 api_name => "open-ils.actor.user.transactions",
1473 notes => <<" NOTES");
1474 Returns a list of open user transactions (mbts objects);
1475 Params are login_session, user_id
1476 Optional third parameter is the transactions type. defaults to all
1479 __PACKAGE__->register_method(
1480 method => "user_transactions",
1481 api_name => "open-ils.actor.user.transactions.have_charge",
1482 notes => <<" NOTES");
1483 Returns a list of all open user transactions (mbts objects) that have an initial charge
1484 Params are login_session, user_id
1485 Optional third parameter is the transactions type. defaults to all
1488 __PACKAGE__->register_method(
1489 method => "user_transactions",
1490 api_name => "open-ils.actor.user.transactions.have_balance",
1491 notes => <<" NOTES");
1492 Returns a list of all open user transactions (mbts objects) that have a balance
1493 Params are login_session, user_id
1494 Optional third parameter is the transactions type. defaults to all
1497 __PACKAGE__->register_method(
1498 method => "user_transactions",
1499 api_name => "open-ils.actor.user.transactions.fleshed",
1500 notes => <<" NOTES");
1501 Returns an object/hash of transaction, circ, title where transaction = an open
1502 user transactions (mbts objects), circ is the attached circluation, and title
1503 is the title the circ points to
1504 Params are login_session, user_id
1505 Optional third parameter is the transactions type. defaults to all
1508 __PACKAGE__->register_method(
1509 method => "user_transactions",
1510 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1511 notes => <<" NOTES");
1512 Returns an object/hash of transaction, circ, title where transaction = an open
1513 user transactions that has an initial charge (mbts objects), circ is the
1514 attached circluation, and title is the title the circ points to
1515 Params are login_session, user_id
1516 Optional third parameter is the transactions type. defaults to all
1519 __PACKAGE__->register_method(
1520 method => "user_transactions",
1521 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1522 notes => <<" NOTES");
1523 Returns an object/hash of transaction, circ, title where transaction = an open
1524 user transaction that has a balance (mbts objects), circ is the attached
1525 circluation, and title is the title the circ points to
1526 Params are login_session, user_id
1527 Optional third parameter is the transaction type. defaults to all
1530 __PACKAGE__->register_method(
1531 method => "user_transactions",
1532 api_name => "open-ils.actor.user.transactions.count",
1533 notes => <<" NOTES");
1534 Returns an object/hash of transaction, circ, title where transaction = an open
1535 user transactions (mbts objects), circ is the attached circluation, and title
1536 is the title the circ points to
1537 Params are login_session, user_id
1538 Optional third parameter is the transactions type. defaults to all
1541 __PACKAGE__->register_method(
1542 method => "user_transactions",
1543 api_name => "open-ils.actor.user.transactions.have_charge.count",
1544 notes => <<" NOTES");
1545 Returns an object/hash of transaction, circ, title where transaction = an open
1546 user transactions that has an initial charge (mbts objects), circ is the
1547 attached circluation, and title is the title the circ points to
1548 Params are login_session, user_id
1549 Optional third parameter is the transactions type. defaults to all
1552 __PACKAGE__->register_method(
1553 method => "user_transactions",
1554 api_name => "open-ils.actor.user.transactions.have_balance.count",
1555 notes => <<" NOTES");
1556 Returns an object/hash of transaction, circ, title where transaction = an open
1557 user transaction that has a balance (mbts objects), circ is the attached
1558 circluation, and title is the title the circ points to
1559 Params are login_session, user_id
1560 Optional third parameter is the transaction type. defaults to all
1563 __PACKAGE__->register_method(
1564 method => "user_transactions",
1565 api_name => "open-ils.actor.user.transactions.have_balance.total",
1566 notes => <<" NOTES");
1567 Returns an object/hash of transaction, circ, title where transaction = an open
1568 user transaction that has a balance (mbts objects), circ is the attached
1569 circluation, and title is the title the circ points to
1570 Params are login_session, user_id
1571 Optional third parameter is the transaction type. defaults to all
1576 sub user_transactions {
1577 my( $self, $client, $login_session, $user_id, $type ) = @_;
1579 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1580 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1581 return $evt if $evt;
1583 my $api = $self->api_name();
1587 if(defined($type)) { @xact = (xact_type => $type);
1589 } else { @xact = (); }
1592 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1593 ->run($login_session => $user_id => $type);
1595 if($api =~ /have_charge/o) {
1597 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1599 } elsif($api =~ /have_balance/o) {
1601 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1604 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1608 if($api =~ /total/o) {
1610 for my $t (@$trans) {
1611 $total += $t->balance_owed;
1614 $logger->debug("Total balance owed by user $user_id: $total");
1618 if($api =~ /count/o) { return scalar @$trans; }
1619 if($api !~ /fleshed/o) { return $trans; }
1622 for my $t (@$trans) {
1624 if( $t->xact_type ne 'circulation' ) {
1625 push @resp, {transaction => $t};
1629 my $circ = $apputils->simple_scalar_request(
1631 "open-ils.cstore.direct.action.circulation.retrieve",
1636 my $title = $apputils->simple_scalar_request(
1638 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1639 $circ->target_copy );
1643 my $u = OpenILS::Utils::ModsParser->new();
1644 $u->start_mods_batch($title->marc());
1645 my $mods = $u->finish_mods_batch();
1646 $mods->doc_id($title->id) if $mods;
1648 push @resp, {transaction => $t, circ => $circ, record => $mods };
1656 __PACKAGE__->register_method(
1657 method => "user_transaction_retrieve",
1658 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1660 notes => <<" NOTES");
1661 Returns a fleshedtransaction record
1663 __PACKAGE__->register_method(
1664 method => "user_transaction_retrieve",
1665 api_name => "open-ils.actor.user.transaction.retrieve",
1667 notes => <<" NOTES");
1668 Returns a transaction record
1670 sub user_transaction_retrieve {
1671 my( $self, $client, $login_session, $bill_id ) = @_;
1673 # XXX I think I'm deprecated... make sure
1675 my $trans = $apputils->simple_scalar_request(
1677 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1681 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1682 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1683 return $evt if $evt;
1685 my $api = $self->api_name();
1686 if($api !~ /fleshed/o) { return $trans; }
1688 if( $trans->xact_type ne 'circulation' ) {
1689 $logger->debug("Returning non-circ transaction");
1690 return {transaction => $trans};
1693 my $circ = $apputils->simple_scalar_request(
1695 "open-ils..direct.action.circulation.retrieve",
1698 return {transaction => $trans} unless $circ;
1699 $logger->debug("Found the circ transaction");
1701 my $title = $apputils->simple_scalar_request(
1703 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1704 $circ->target_copy );
1706 return {transaction => $trans, circ => $circ } unless $title;
1707 $logger->debug("Found the circ title");
1711 my $u = OpenILS::Utils::ModsParser->new();
1712 $u->start_mods_batch($title->marc());
1713 $mods = $u->finish_mods_batch();
1715 if ($title->id == OILS_PRECAT_RECORD) {
1716 my $copy = $apputils->simple_scalar_request(
1718 "open-ils.cstore.direct.asset.copy.retrieve",
1719 $circ->target_copy );
1721 $mods = new Fieldmapper::metabib::virtual_record;
1722 $mods->doc_id(OILS_PRECAT_RECORD);
1723 $mods->title($copy->dummy_title);
1724 $mods->author($copy->dummy_author);
1728 $logger->debug("MODSized the circ title");
1730 return {transaction => $trans, circ => $circ, record => $mods };
1734 __PACKAGE__->register_method(
1735 method => "hold_request_count",
1736 api_name => "open-ils.actor.user.hold_requests.count",
1739 notes => <<" NOTES");
1740 Returns hold ready/total counts
1742 sub hold_request_count {
1743 my( $self, $client, $login_session, $userid ) = @_;
1745 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1746 $login_session, $userid, 'VIEW_HOLD' );
1747 return $evt if $evt;
1750 my $holds = $apputils->simple_scalar_request(
1752 "open-ils.cstore.direct.action.hold_request.search.atomic",
1755 fulfillment_time => {"=" => undef },
1756 cancel_time => undef,
1761 for my $h (@$holds) {
1762 next unless $h->capture_time and $h->current_copy;
1764 my $copy = $apputils->simple_scalar_request(
1766 "open-ils.cstore.direct.asset.copy.retrieve",
1770 if ($copy and $copy->status == 8) {
1775 return { total => scalar(@$holds), ready => scalar(@ready) };
1779 __PACKAGE__->register_method(
1780 method => "checkedout_count",
1781 api_name => "open-ils.actor.user.checked_out.count__",
1783 notes => <<" NOTES");
1784 Returns a transaction record
1788 sub checkedout_count {
1789 my( $self, $client, $login_session, $userid ) = @_;
1791 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1792 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1793 return $evt if $evt;
1795 my $circs = $apputils->simple_scalar_request(
1797 "open-ils.cstore.direct.action.circulation.search.atomic",
1798 { usr => $userid, stop_fines => undef }
1799 #{ usr => $userid, checkin_time => {"=" => undef } }
1802 my $parser = DateTime::Format::ISO8601->new;
1805 for my $c (@$circs) {
1806 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1807 my $due = $due_dt->epoch;
1809 if ($due < DateTime->today->epoch) {
1814 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1818 __PACKAGE__->register_method(
1819 method => "checked_out",
1820 api_name => "open-ils.actor.user.checked_out",
1824 Returns a structure of circulations objects sorted by
1825 out, overdue, lost, claims_returned, long_overdue.
1826 A list of IDs are returned of each type.
1827 lost, long_overdue, and claims_returned circ will not
1828 be "finished" (there is an outstanding balance or some
1829 other pending action on the circ).
1831 The .count method also includes a 'total' field which
1832 sums all "open" circs
1836 __PACKAGE__->register_method(
1837 method => "checked_out",
1838 api_name => "open-ils.actor.user.checked_out.count",
1841 signature => q/@see open-ils.actor.user.checked_out/
1845 my( $self, $conn, $auth, $userid ) = @_;
1847 my $e = new_editor(authtoken=>$auth);
1848 return $e->event unless $e->checkauth;
1850 if( $userid ne $e->requestor->id ) {
1851 my $user = $e->retrieve_actor_user($userid) or return $e->event;
1852 unless($e->allowed('VIEW_CIRCULATIONS', $user->home_ou)) {
1854 # see if there is a friend link allowing circ.view perms
1855 my $allowed = OpenILS::Application::Actor::Friends->friend_perm_allowed(
1856 $e, $userid, $e->requestor->id, 'circ.view');
1857 return $e->event unless $allowed;
1861 my $count = $self->api_name =~ /count/;
1862 return _checked_out( $count, $e, $userid );
1866 my( $iscount, $e, $userid ) = @_;
1867 my $meth = 'open-ils.storage.actor.user.checked_out';
1868 $meth = "$meth.count" if $iscount;
1869 return $U->storagereq($meth, $userid);
1873 sub _checked_out_WHAT {
1874 my( $iscount, $e, $userid ) = @_;
1876 my $circs = $e->search_action_circulation(
1877 { usr => $userid, stop_fines => undef });
1879 my $mcircs = $e->search_action_circulation(
1882 checkin_time => undef,
1883 xact_finish => undef,
1887 push( @$circs, @$mcircs );
1889 my $parser = DateTime::Format::ISO8601->new;
1891 # split the circs up into overdue and not-overdue circs
1893 for my $c (@$circs) {
1894 if( $c->due_date ) {
1895 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1896 my $due = $due_dt->epoch;
1897 if ($due < DateTime->today->epoch) {
1898 push @overdue, $c->id;
1907 # grab all of the lost, claims-returned, and longoverdue circs
1908 #my $open = $e->search_action_circulation(
1909 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1912 # these items have stop_fines, but no xact_finish, so money
1913 # is owed on them and they have not been checked in
1914 my $open = $e->search_action_circulation(
1917 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1918 xact_finish => undef,
1919 checkin_time => undef,
1924 my( @lost, @cr, @lo );
1925 for my $c (@$open) {
1926 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1927 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1928 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1934 total => @$circs + @lost + @cr + @lo,
1935 out => scalar(@out),
1936 overdue => scalar(@overdue),
1937 lost => scalar(@lost),
1938 claims_returned => scalar(@cr),
1939 long_overdue => scalar(@lo)
1945 overdue => \@overdue,
1947 claims_returned => \@cr,
1948 long_overdue => \@lo
1954 __PACKAGE__->register_method(
1955 method => "checked_in_with_fines",
1956 api_name => "open-ils.actor.user.checked_in_with_fines",
1959 signature => q/@see open-ils.actor.user.checked_out/
1961 sub checked_in_with_fines {
1962 my( $self, $conn, $auth, $userid ) = @_;
1964 my $e = new_editor(authtoken=>$auth);
1965 return $e->event unless $e->checkauth;
1967 if( $userid ne $e->requestor->id ) {
1968 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1971 # money is owed on these items and they are checked in
1972 my $open = $e->search_action_circulation(
1975 xact_finish => undef,
1976 checkin_time => { "!=" => undef },
1981 my( @lost, @cr, @lo );
1982 for my $c (@$open) {
1983 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1984 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1985 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1990 claims_returned => \@cr,
1991 long_overdue => \@lo
2003 __PACKAGE__->register_method(
2004 method => "user_transaction_history",
2005 api_name => "open-ils.actor.user.transactions.history",
2007 notes => <<" NOTES");
2008 Returns a list of billable transaction ids for a user, optionally by type
2010 __PACKAGE__->register_method(
2011 method => "user_transaction_history",
2012 api_name => "open-ils.actor.user.transactions.history.have_charge",
2014 notes => <<" NOTES");
2015 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2017 __PACKAGE__->register_method(
2018 method => "user_transaction_history",
2019 api_name => "open-ils.actor.user.transactions.history.have_balance",
2022 notes => <<" NOTES");
2023 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2025 __PACKAGE__->register_method(
2026 method => "user_transaction_history",
2027 api_name => "open-ils.actor.user.transactions.history.still_open",
2029 notes => <<" NOTES");
2030 Returns a list of billable transaction ids for a user that are not finished
2032 __PACKAGE__->register_method(
2033 method => "user_transaction_history",
2034 api_name => "open-ils.actor.user.transactions.history.have_bill",
2037 notes => <<" NOTES");
2038 Returns a list of billable transaction ids for a user that has billings
2041 sub user_transaction_history {
2042 my( $self, $conn, $auth, $userid, $type ) = @_;
2044 # run inside of a transaction to prevent replication delays
2045 my $e = new_editor(xact=>1, authtoken=>$auth);
2046 return $e->die_event unless $e->checkauth;
2048 if( $e->requestor->id ne $userid ) {
2049 return $e->die_event
2050 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2053 my $api = $self->api_name;
2054 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2056 my @xacts = @{ $e->search_money_billable_transaction(
2057 [ { usr => $userid, @xact_finish },
2059 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2060 order_by => { mbt => 'xact_start DESC' },
2068 #my @mbts = _make_mbts( @xacts );
2069 my @mbts = $U->make_mbts( @xacts );
2071 if(defined($type)) {
2072 @mbts = grep { $_->xact_type eq $type } @mbts;
2075 if($api =~ /have_balance/o) {
2076 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2079 if($api =~ /have_charge/o) {
2080 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2083 if($api =~ /have_bill/o) {
2084 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2092 __PACKAGE__->register_method(
2093 method => "user_perms",
2094 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2096 notes => <<" NOTES");
2097 Returns a list of permissions
2100 my( $self, $client, $authtoken, $user ) = @_;
2102 my( $staff, $evt ) = $apputils->checkses($authtoken);
2103 return $evt if $evt;
2105 $user ||= $staff->id;
2107 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2111 return $apputils->simple_scalar_request(
2113 "open-ils.storage.permission.user_perms.atomic",
2117 __PACKAGE__->register_method(
2118 method => "retrieve_perms",
2119 api_name => "open-ils.actor.permissions.retrieve",
2120 notes => <<" NOTES");
2121 Returns a list of permissions
2123 sub retrieve_perms {
2124 my( $self, $client ) = @_;
2125 return $apputils->simple_scalar_request(
2127 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2128 { id => { '!=' => undef } }
2132 __PACKAGE__->register_method(
2133 method => "retrieve_groups",
2134 api_name => "open-ils.actor.groups.retrieve",
2135 notes => <<" NOTES");
2136 Returns a list of user groupss
2138 sub retrieve_groups {
2139 my( $self, $client ) = @_;
2140 return new_editor()->retrieve_all_permission_grp_tree();
2143 __PACKAGE__->register_method(
2144 method => "retrieve_org_address",
2145 api_name => "open-ils.actor.org_unit.address.retrieve",
2146 notes => <<' NOTES');
2147 Returns an org_unit address by ID
2148 @param An org_address ID
2150 sub retrieve_org_address {
2151 my( $self, $client, $id ) = @_;
2152 return $apputils->simple_scalar_request(
2154 "open-ils.cstore.direct.actor.org_address.retrieve",
2159 __PACKAGE__->register_method(
2160 method => "retrieve_groups_tree",
2161 api_name => "open-ils.actor.groups.tree.retrieve",
2162 notes => <<" NOTES");
2163 Returns a list of user groups
2165 sub retrieve_groups_tree {
2166 my( $self, $client ) = @_;
2167 return new_editor()->search_permission_grp_tree(
2172 flesh_fields => { pgt => ["children"] },
2173 order_by => { pgt => 'name'}
2180 __PACKAGE__->register_method(
2181 method => "add_user_to_groups",
2182 api_name => "open-ils.actor.user.set_groups",
2183 notes => <<" NOTES");
2184 Adds a user to one or more permission groups
2187 sub add_user_to_groups {
2188 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2190 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2191 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2192 return $evt if $evt;
2194 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2195 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2196 return $evt if $evt;
2198 $apputils->simplereq(
2200 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2202 for my $group (@$groups) {
2203 my $link = Fieldmapper::permission::usr_grp_map->new;
2205 $link->usr($userid);
2207 my $id = $apputils->simplereq(
2209 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2215 __PACKAGE__->register_method(
2216 method => "get_user_perm_groups",
2217 api_name => "open-ils.actor.user.get_groups",
2218 notes => <<" NOTES");
2219 Retrieve a user's permission groups.
2223 sub get_user_perm_groups {
2224 my( $self, $client, $authtoken, $userid ) = @_;
2226 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2227 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2228 return $evt if $evt;
2230 return $apputils->simplereq(
2232 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2236 __PACKAGE__->register_method(
2237 method => "get_user_work_ous",
2238 api_name => "open-ils.actor.user.get_work_ous",
2239 notes => <<" NOTES");
2240 Retrieve a user's work org units.
2242 __PACKAGE__->register_method(
2243 method => "get_user_work_ous",
2244 api_name => "open-ils.actor.user.get_work_ous.ids",
2245 notes => <<" NOTES");
2246 Retrieve a user's work org units.
2250 sub get_user_work_ous {
2251 my( $self, $client, $auth, $userid ) = @_;
2252 my $e = new_editor(authtoken=>$auth);
2253 return $e->event unless $e->checkauth;
2254 $userid ||= $e->requestor->id;
2256 if($e->requestor->id != $userid) {
2257 my $user = $e->retrieve_actor_user($userid)
2258 or return $e->event;
2259 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2262 return $e->search_permission_usr_work_ou_map({usr => $userid})
2263 unless $self->api_name =~ /.ids$/;
2265 # client just wants a list of org IDs
2266 return $U->get_user_work_ou_ids($e, $userid);
2272 __PACKAGE__->register_method (
2273 method => 'register_workstation',
2274 api_name => 'open-ils.actor.workstation.register.override',
2275 signature => q/@see open-ils.actor.workstation.register/);
2277 __PACKAGE__->register_method (
2278 method => 'register_workstation',
2279 api_name => 'open-ils.actor.workstation.register',
2281 Registers a new workstion in the system
2282 @param authtoken The login session key
2283 @param name The name of the workstation id
2284 @param owner The org unit that owns this workstation
2285 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2286 if the name is already in use.
2289 sub register_workstation {
2290 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2292 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2293 return $e->die_event unless $e->checkauth;
2294 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2295 my $existing = $e->search_actor_workstation({name => $name})->[0];
2299 if( $self->api_name =~ /override/o ) {
2300 # workstation with the given name exists.
2302 if($owner ne $existing->owning_lib) {
2303 # if necessary, update the owning_lib of the workstation
2305 $logger->info("changing owning lib of workstation ".$existing->id.
2306 " from ".$existing->owning_lib." to $owner");
2307 return $e->die_event unless
2308 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2310 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2312 $existing->owning_lib($owner);
2313 return $e->die_event unless $e->update_actor_workstation($existing);
2319 "attempt to register an existing workstation. returning existing ID");
2322 return $existing->id;
2325 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2329 my $ws = Fieldmapper::actor::workstation->new;
2330 $ws->owning_lib($owner);
2332 $e->create_actor_workstation($ws) or return $e->die_event;
2334 return $ws->id; # note: editor sets the id on the new object for us
2337 __PACKAGE__->register_method (
2338 method => 'workstation_list',
2339 api_name => 'open-ils.actor.workstation.list',
2341 Returns a list of workstations registered at the given location
2342 @param authtoken The login session key
2343 @param ids A list of org_unit.id's for the workstation owners
2346 sub workstation_list {
2347 my( $self, $conn, $authtoken, @orgs ) = @_;
2349 my $e = new_editor(authtoken=>$authtoken);
2350 return $e->event unless $e->checkauth;
2355 unless $e->allowed('REGISTER_WORKSTATION', $o);
2356 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2367 __PACKAGE__->register_method (
2368 method => 'fetch_patron_note',
2369 api_name => 'open-ils.actor.note.retrieve.all',
2372 Returns a list of notes for a given user
2373 Requestor must have VIEW_USER permission if pub==false and
2374 @param authtoken The login session key
2375 @param args Hash of params including
2376 patronid : the patron's id
2377 pub : true if retrieving only public notes
2381 sub fetch_patron_note {
2382 my( $self, $conn, $authtoken, $args ) = @_;
2383 my $patronid = $$args{patronid};
2385 my($reqr, $evt) = $U->checkses($authtoken);
2386 return $evt if $evt;
2389 ($patron, $evt) = $U->fetch_user($patronid);
2390 return $evt if $evt;
2393 if( $patronid ne $reqr->id ) {
2394 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2395 return $evt if $evt;
2397 return $U->cstorereq(
2398 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2399 { usr => $patronid, pub => 't' } );
2402 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2403 return $evt if $evt;
2405 return $U->cstorereq(
2406 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2409 __PACKAGE__->register_method (
2410 method => 'create_user_note',
2411 api_name => 'open-ils.actor.note.create',
2413 Creates a new note for the given user
2414 @param authtoken The login session key
2415 @param note The note object
2418 sub create_user_note {
2419 my( $self, $conn, $authtoken, $note ) = @_;
2420 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2421 return $e->die_event unless $e->checkauth;
2423 my $user = $e->retrieve_actor_user($note->usr)
2424 or return $e->die_event;
2426 return $e->die_event unless
2427 $e->allowed('UPDATE_USER',$user->home_ou);
2429 $note->creator($e->requestor->id);
2430 $e->create_actor_usr_note($note) or return $e->die_event;
2436 __PACKAGE__->register_method (
2437 method => 'delete_user_note',
2438 api_name => 'open-ils.actor.note.delete',
2440 Deletes a note for the given user
2441 @param authtoken The login session key
2442 @param noteid The note id
2445 sub delete_user_note {
2446 my( $self, $conn, $authtoken, $noteid ) = @_;
2448 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2449 return $e->die_event unless $e->checkauth;
2450 my $note = $e->retrieve_actor_usr_note($noteid)
2451 or return $e->die_event;
2452 my $user = $e->retrieve_actor_user($note->usr)
2453 or return $e->die_event;
2454 return $e->die_event unless
2455 $e->allowed('UPDATE_USER', $user->home_ou);
2457 $e->delete_actor_usr_note($note) or return $e->die_event;
2463 __PACKAGE__->register_method (
2464 method => 'update_user_note',
2465 api_name => 'open-ils.actor.note.update',
2467 @param authtoken The login session key
2468 @param note The note
2472 sub update_user_note {
2473 my( $self, $conn, $auth, $note ) = @_;
2474 my $e = new_editor(authtoken=>$auth, xact=>1);
2475 return $e->event unless $e->checkauth;
2476 my $patron = $e->retrieve_actor_user($note->usr)
2477 or return $e->event;
2478 return $e->event unless
2479 $e->allowed('UPDATE_USER', $patron->home_ou);
2480 $e->update_actor_user_note($note)
2481 or return $e->event;
2489 __PACKAGE__->register_method (
2490 method => 'create_closed_date',
2491 api_name => 'open-ils.actor.org_unit.closed_date.create',
2493 Creates a new closing entry for the given org_unit
2494 @param authtoken The login session key
2495 @param note The closed_date object
2498 sub create_closed_date {
2499 my( $self, $conn, $authtoken, $cd ) = @_;
2501 my( $user, $evt ) = $U->checkses($authtoken);
2502 return $evt if $evt;
2504 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2505 return $evt if $evt;
2507 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2509 my $id = $U->storagereq(
2510 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2511 return $U->DB_UPDATE_FAILED($cd) unless $id;
2516 __PACKAGE__->register_method (
2517 method => 'delete_closed_date',
2518 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2520 Deletes a closing entry for the given org_unit
2521 @param authtoken The login session key
2522 @param noteid The close_date id
2525 sub delete_closed_date {
2526 my( $self, $conn, $authtoken, $cd ) = @_;
2528 my( $user, $evt ) = $U->checkses($authtoken);
2529 return $evt if $evt;
2532 ($cd_obj, $evt) = fetch_closed_date($cd);
2533 return $evt if $evt;
2535 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2536 return $evt if $evt;
2538 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2540 my $stat = $U->storagereq(
2541 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2542 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2547 __PACKAGE__->register_method(
2548 method => 'usrname_exists',
2549 api_name => 'open-ils.actor.username.exists',
2551 Returns 1 if the requested username exists, returns 0 otherwise
2555 sub usrname_exists {
2556 my( $self, $conn, $auth, $usrname ) = @_;
2557 my $e = new_editor(authtoken=>$auth);
2558 return $e->event unless $e->checkauth;
2559 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2560 return $$a[0] if $a and @$a;
2564 __PACKAGE__->register_method(
2565 method => 'barcode_exists',
2566 api_name => 'open-ils.actor.barcode.exists',
2569 Returns 1 if the requested barcode exists, returns 0 otherwise
2573 sub barcode_exists {
2574 my( $self, $conn, $auth, $barcode ) = @_;
2575 my $e = new_editor(authtoken=>$auth);
2576 return $e->event unless $e->checkauth;
2577 my $card = $e->search_actor_card({barcode => $barcode});
2583 #return undef unless @$card;
2584 #return $card->[0]->usr;
2588 __PACKAGE__->register_method(
2589 method => 'retrieve_net_levels',
2590 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2593 sub retrieve_net_levels {
2594 my( $self, $conn, $auth ) = @_;
2595 my $e = new_editor(authtoken=>$auth);
2596 return $e->event unless $e->checkauth;
2597 return $e->retrieve_all_config_net_access_level();
2601 __PACKAGE__->register_method(
2602 method => 'fetch_org_by_shortname',
2603 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2605 sub fetch_org_by_shortname {
2606 my( $self, $conn, $sname ) = @_;
2607 my $e = new_editor();
2608 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2609 return $e->event unless $org;
2614 __PACKAGE__->register_method(
2615 method => 'session_home_lib',
2616 api_name => 'open-ils.actor.session.home_lib',
2619 sub session_home_lib {
2620 my( $self, $conn, $auth ) = @_;
2621 my $e = new_editor(authtoken=>$auth);
2622 return undef unless $e->checkauth;
2623 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2624 return $org->shortname;
2627 __PACKAGE__->register_method(
2628 method => 'session_safe_token',
2629 api_name => 'open-ils.actor.session.safe_token',
2631 Returns a hashed session ID that is safe for export to the world.
2632 This safe token will expire after 1 hour of non-use.
2633 @param auth Active authentication token
2637 sub session_safe_token {
2638 my( $self, $conn, $auth ) = @_;
2639 my $e = new_editor(authtoken=>$auth);
2640 return undef unless $e->checkauth;
2642 my $safe_token = md5_hex($auth);
2644 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2646 # Add more like the following if needed...
2648 "safe-token-home_lib-shortname-$safe_token",
2649 $e->retrieve_actor_org_unit(
2650 $e->requestor->home_ou
2659 __PACKAGE__->register_method(
2660 method => 'safe_token_home_lib',
2661 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2663 Returns the home library shortname from the session
2664 asscociated with a safe token from generated by
2665 open-ils.actor.session.safe_token.
2666 @param safe_token Active safe token
2670 sub safe_token_home_lib {
2671 my( $self, $conn, $safe_token ) = @_;
2673 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2674 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2679 __PACKAGE__->register_method(
2680 method => 'slim_tree',
2681 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2684 my $tree = new_editor()->search_actor_org_unit(
2686 {"parent_ou" => undef },
2689 flesh_fields => { aou => ['children'] },
2690 order_by => { aou => 'name'},
2691 select => { aou => ["id","shortname", "name"]},
2696 return trim_tree($tree);
2702 return undef unless $tree;
2704 code => $tree->shortname,
2705 name => $tree->name,
2707 if( $tree->children and @{$tree->children} ) {
2708 $htree->{children} = [];
2709 for my $c (@{$tree->children}) {
2710 push( @{$htree->{children}}, trim_tree($c) );
2718 __PACKAGE__->register_method(
2719 method => "update_penalties",
2720 api_name => "open-ils.actor.user.penalties.update");
2722 sub update_penalties {
2723 my($self, $conn, $auth, $user_id) = @_;
2724 my $e = new_editor(authtoken=>$auth, xact => 1);
2725 return $e->die_event unless $e->checkauth;
2726 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2727 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2728 my $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $e->requestor->ws_ou);
2729 return $evt if $evt;
2735 __PACKAGE__->register_method(
2736 method => "apply_penalty",
2737 api_name => "open-ils.actor.user.penalty.apply");
2740 my($self, $conn, $auth, $penalty) = @_;
2741 my $e = new_editor(authtoken=>$auth, xact => 1);
2742 return $e->die_event unless $e->checkauth;
2743 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2744 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2746 # is it already applied?
2747 return 1 if $e->search_actor_user_standing_penalty(
2748 { usr => $penalty->usr,
2749 standing_penalty => $penalty->standing_penalty,
2750 org_unit => $penalty->org_unit
2753 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
2755 return $penalty->id;
2758 __PACKAGE__->register_method(
2759 method => "remove_penalty",
2760 api_name => "open-ils.actor.user.penalty.remove");
2762 sub remove_penalty {
2763 my($self, $conn, $auth, $penalty) = @_;
2764 my $e = new_editor(authtoken=>$auth, xact => 1);
2765 return $e->die_event unless $e->checkauth;
2766 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2767 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2769 $e->delete_actor_user_standing_penalty($penalty) or return $e->die_event;
2774 __PACKAGE__->register_method(
2775 method => "update_penalty_note",
2776 api_name => "open-ils.actor.user.penalty.note.update");
2778 sub update_penalty_note {
2779 my($self, $conn, $auth, $penalty_ids, $note) = @_;
2780 my $e = new_editor(authtoken=>$auth, xact => 1);
2781 return $e->die_event unless $e->checkauth;
2782 for my $penalty_id (@$penalty_ids) {
2783 my $penalty = $e->search_actor_user_standing_penalty( { id => $penalty_id } )->[0];
2784 if (! $penalty ) { return $e->die_event; }
2785 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2786 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2788 $penalty->note( $note ); $penalty->ischanged( 1 );
2790 $e->update_actor_user_standing_penalty($penalty) or return $e->die_event;
2796 __PACKAGE__->register_method(
2797 method => "ranged_penalty_thresholds",
2798 api_name => "open-ils.actor.grp_penalty_threshold.ranged.retrieve",
2802 sub ranged_penalty_thresholds {
2803 my($self, $conn, $auth, $context_org) = @_;
2804 my $e = new_editor(authtoken=>$auth);
2805 return $e->event unless $e->checkauth;
2806 return $e->event unless $e->allowed('VIEW_GROUP_PENALTY_THRESHOLD', $context_org);
2807 my $list = $e->search_permission_grp_penalty_threshold([
2808 {org_unit => $U->get_org_ancestors($context_org)},
2809 {order_by => {pgpt => 'id'}}
2811 $conn->respond($_) for @$list;
2817 __PACKAGE__->register_method(
2818 method => "user_retrieve_fleshed_by_id",
2820 api_name => "open-ils.actor.user.fleshed.retrieve",);
2822 sub user_retrieve_fleshed_by_id {
2823 my( $self, $client, $auth, $user_id, $fields ) = @_;
2824 my $e = new_editor(authtoken => $auth);
2825 return $e->event unless $e->checkauth;
2827 if( $e->requestor->id != $user_id ) {
2828 return $e->event unless $e->allowed('VIEW_USER');
2834 "standing_penalties",
2838 "stat_cat_entries" ];
2839 return new_flesh_user($user_id, $fields, $e);
2843 sub new_flesh_user {
2846 my $fields = shift || [];
2849 my $fetch_penalties = 0;
2850 if(grep {$_ eq 'standing_penalties'} @$fields) {
2851 $fields = [grep {$_ ne 'standing_penalties'} @$fields];
2852 $fetch_penalties = 1;
2855 my $user = $e->retrieve_actor_user(
2860 "flesh_fields" => { "au" => $fields }
2863 ) or return $e->event;
2866 if( grep { $_ eq 'addresses' } @$fields ) {
2868 $user->addresses([]) unless @{$user->addresses};
2870 if( ref $user->billing_address ) {
2871 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2872 push( @{$user->addresses}, $user->billing_address );
2876 if( ref $user->mailing_address ) {
2877 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2878 push( @{$user->addresses}, $user->mailing_address );
2883 if($fetch_penalties) {
2884 # grab the user penalties ranged for this location
2885 $user->standing_penalties(
2886 $e->search_actor_user_standing_penalty([
2888 org_unit => $U->get_org_ancestors($e->requestor->ws_ou)
2891 flesh_fields => {ausp => ['standing_penalty']}
2898 $user->clear_passwd();
2905 __PACKAGE__->register_method(
2906 method => "user_retrieve_parts",
2907 api_name => "open-ils.actor.user.retrieve.parts",);
2909 sub user_retrieve_parts {
2910 my( $self, $client, $auth, $user_id, $fields ) = @_;
2911 my $e = new_editor(authtoken => $auth);
2912 return $e->event unless $e->checkauth;
2913 if( $e->requestor->id != $user_id ) {
2914 return $e->event unless $e->allowed('VIEW_USER');
2917 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2918 push(@resp, $user->$_()) for(@$fields);
2924 __PACKAGE__->register_method(
2925 method => 'user_opt_in_enabled',
2926 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2928 @return 1 if user opt-in is globally enabled, 0 otherwise.
2931 sub user_opt_in_enabled {
2932 my($self, $conn) = @_;
2933 my $sc = OpenSRF::Utils::SettingsClient->new;
2934 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2939 __PACKAGE__->register_method(
2940 method => 'user_opt_in_at_org',
2941 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2943 @param $auth The auth token
2944 @param user_id The ID of the user to test
2945 @return 1 if the user has opted in at the specified org,
2946 event on error, and 0 otherwise. /);
2947 sub user_opt_in_at_org {
2948 my($self, $conn, $auth, $user_id) = @_;
2950 # see if we even need to enforce the opt-in value
2951 return 1 unless user_opt_in_enabled($self);
2953 my $e = new_editor(authtoken => $auth);
2954 return $e->event unless $e->checkauth;
2955 my $org_id = $e->requestor->ws_ou;
2957 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2958 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2960 # user is automatically opted-in at the home org
2961 return 1 if $user->home_ou eq $org_id;
2963 my $vals = $e->search_actor_usr_org_unit_opt_in(
2964 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2970 __PACKAGE__->register_method(
2971 method => 'create_user_opt_in_at_org',
2972 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2974 @param $auth The auth token
2975 @param user_id The ID of the user to test
2976 @return The ID of the newly created object, event on error./);
2978 sub create_user_opt_in_at_org {
2979 my($self, $conn, $auth, $user_id) = @_;
2981 my $e = new_editor(authtoken => $auth, xact=>1);
2982 return $e->die_event unless $e->checkauth;
2983 my $org_id = $e->requestor->ws_ou;
2985 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2986 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2988 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2990 $opt_in->org_unit($org_id);
2991 $opt_in->usr($user_id);
2992 $opt_in->staff($e->requestor->id);
2993 $opt_in->opt_in_ts('now');
2994 $opt_in->opt_in_ws($e->requestor->wsid);
2996 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2997 or return $e->die_event;
3005 __PACKAGE__->register_method (
3006 method => 'retrieve_org_hours',
3007 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
3009 Returns the hours of operation for a specified org unit
3010 @param authtoken The login session key
3011 @param org_id The org_unit ID
3015 sub retrieve_org_hours {
3016 my($self, $conn, $auth, $org_id) = @_;
3017 my $e = new_editor(authtoken => $auth);
3018 return $e->die_event unless $e->checkauth;
3019 $org_id ||= $e->requestor->ws_ou;
3020 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);
3024 __PACKAGE__->register_method (
3025 method => 'verify_user_password',
3026 api_name => 'open-ils.actor.verify_user_password',
3028 Given a barcode or username and the MD5 encoded password,
3029 returns 1 if the password is correct. Returns 0 otherwise.
3033 sub verify_user_password {
3034 my($self, $conn, $auth, $barcode, $username, $password) = @_;
3035 my $e = new_editor(authtoken => $auth);
3036 return $e->die_event unless $e->checkauth;
3038 my $user_by_barcode;
3039 my $user_by_username;
3041 my $card = $e->search_actor_card([
3042 {barcode => $barcode},
3043 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return 0;
3044 $user_by_barcode = $card->usr;
3045 $user = $user_by_barcode;
3048 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return 0;
3049 $user = $user_by_username;
3051 return 0 if (!$user);
3052 return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3053 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3054 return 1 if $user->passwd eq $password;
3058 __PACKAGE__->register_method (
3059 method => 'retrieve_usr_id_via_barcode_or_usrname',
3060 api_name => "open-ils.actor.user.retrieve_id_by_barcode_or_username",
3062 Given a barcode or username returns the id for the user or
3067 sub retrieve_usr_id_via_barcode_or_usrname {
3068 my($self, $conn, $auth, $barcode, $username) = @_;
3069 my $e = new_editor(authtoken => $auth);
3070 return $e->die_event unless $e->checkauth;
3072 my $user_by_barcode;
3073 my $user_by_username;
3075 my $card = $e->search_actor_card([
3076 {barcode => $barcode},
3077 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
3078 $user_by_barcode = $card->usr;
3079 $user = $user_by_barcode;
3082 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
3084 $user = $user_by_username;
3086 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if (!$user);
3087 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3088 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3093 __PACKAGE__->register_method (
3094 method => 'merge_users',
3095 api_name => 'open-ils.actor.user.merge',
3098 Given a source user and destination user, transfer all data from the source
3099 to the dest. user and delete the source user. All user related data is
3100 transferred, including circulations, holds, bookbags, etc.
3106 my($self, $conn, $auth, $master_id, $options, @user_ids) = @_;
3107 my $e = new_editor(xact => 1, authtoken => $auth);
3108 return $e->die_event unless $e->checkauth;
3110 for my $src_id (@user_ids) {
3111 my $src_user = $e->retrieve_actor_user($src_id) or return $e->die_event;
3112 my $master_user = $e->retrieve_actor_user($master_id) or return $e->die_event;
3114 return $e->die_event unless $e->allowed('MERGE_USERS', $src_user->home_ou);
3115 if($src_user->home_ou ne $master_user->home_ou) {
3116 return $e->die_event unless $e->allowed('MERGE_USERS', $master_user->home_ou);
3119 return $e->die_event unless
3120 $e->json_query({from => ['actor.usr_merge', $src_id, $master_id]});
3129 __PACKAGE__->register_method (
3130 method => 'retrieve_friends',
3131 api_name => 'open-ils.actor.friends.retrieve',
3134 returns { confirmed: [], pending_out: [], pending_in: []}
3135 pending_out are users I'm requesting friendship with
3136 pending_in are users requesting friendship with me
3141 sub retrieve_friends {
3142 my($self, $conn, $auth, $user_id, $options) = @_;
3143 my $e = new_editor(authtoken => $auth);
3144 return $e->event unless $e->checkauth;
3145 $user_id ||= $e->requestor->id;
3147 if($user_id != $e->requestor->id) {
3148 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3149 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3152 return OpenILS::Application::Actor::Friends->retrieve_friends(
3153 $e, $user_id, $options);
3158 __PACKAGE__->register_method (
3159 method => 'apply_friend_perms',
3160 api_name => 'open-ils.actor.friends.perms.apply',
3166 sub apply_friend_perms {
3167 my($self, $conn, $auth, $user_id, $delegate_id, @perms) = @_;
3168 my $e = new_editor(authtoken => $auth, xact => 1);
3169 return $e->event unless $e->checkauth;
3171 if($user_id != $e->requestor->id) {
3172 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3173 return $e->die_event unless $e->allowed('VIEW_USER', $user->home_ou);
3176 for my $perm (@perms) {
3178 OpenILS::Application::Actor::Friends->apply_friend_perm(
3179 $e, $user_id, $delegate_id, $perm);
3180 return $evt if $evt;
3188 __PACKAGE__->register_method (
3189 method => 'update_user_pending_address',
3190 api_name => 'open-ils.actor.user.address.pending.cud'
3193 sub update_user_pending_address {
3194 my($self, $conn, $auth, $addr) = @_;
3195 my $e = new_editor(authtoken => $auth, xact => 1);
3196 return $e->event unless $e->checkauth;
3198 if($addr->usr != $e->requestor->id) {
3199 my $user = $e->retrieve_actor_user($addr->usr) or return $e->die_event;
3200 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3204 $e->create_actor_user_address($addr) or return $e->die_event;
3205 } elsif($addr->isdeleted) {
3206 $e->delete_actor_user_address($addr) or return $e->die_event;
3208 $e->update_actor_user_address($addr) or return $e->die_event;