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",
930 api_name => "open-ils.actor.user.retrieve",);
933 my ($self, $client, $auth, $id) = @_;
934 my $e = new_editor(authtoken=>$auth);
935 return $e->event unless $e->checkauth;
936 my $user = $e->retrieve_actor_user($id)
938 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
944 __PACKAGE__->register_method(
945 method => "get_org_types",
946 api_name => "open-ils.actor.org_types.retrieve",);
949 return $U->get_org_types();
954 __PACKAGE__->register_method(
955 method => "get_user_ident_types",
956 api_name => "open-ils.actor.user.ident_types.retrieve",
959 sub get_user_ident_types {
960 return $ident_types if $ident_types;
961 return $ident_types =
962 new_editor()->retrieve_all_config_identification_type();
968 __PACKAGE__->register_method(
969 method => "get_org_unit",
970 api_name => "open-ils.actor.org_unit.retrieve",
974 my( $self, $client, $user_session, $org_id ) = @_;
975 my $e = new_editor(authtoken => $user_session);
977 return $e->event unless $e->checkauth;
978 $org_id = $e->requestor->ws_ou;
980 my $o = $e->retrieve_actor_org_unit($org_id)
985 __PACKAGE__->register_method(
986 method => "search_org_unit",
987 api_name => "open-ils.actor.org_unit_list.search",
990 sub search_org_unit {
992 my( $self, $client, $field, $value ) = @_;
994 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
996 "open-ils.cstore.direct.actor.org_unit.search.atomic",
997 { $field => $value } );
1003 # build the org tree
1005 __PACKAGE__->register_method(
1006 method => "get_org_tree",
1007 api_name => "open-ils.actor.org_tree.retrieve",
1009 note => "Returns the entire org tree structure",
1015 return $U->get_org_tree($client->session->session_locale);
1019 __PACKAGE__->register_method(
1020 method => "get_org_descendants",
1021 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1024 # depth is optional. org_unit is the id
1025 sub get_org_descendants {
1026 my( $self, $client, $org_unit, $depth ) = @_;
1028 if(ref $org_unit eq 'ARRAY') {
1031 for my $i (0..scalar(@$org_unit)-1) {
1032 my $list = $U->simple_scalar_request(
1034 "open-ils.storage.actor.org_unit.descendants.atomic",
1035 $org_unit->[$i], $depth->[$i] );
1036 push(@trees, $U->build_org_tree($list));
1041 my $orglist = $apputils->simple_scalar_request(
1043 "open-ils.storage.actor.org_unit.descendants.atomic",
1044 $org_unit, $depth );
1045 return $U->build_org_tree($orglist);
1050 __PACKAGE__->register_method(
1051 method => "get_org_ancestors",
1052 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1055 # depth is optional. org_unit is the id
1056 sub get_org_ancestors {
1057 my( $self, $client, $org_unit, $depth ) = @_;
1058 my $orglist = $apputils->simple_scalar_request(
1060 "open-ils.storage.actor.org_unit.ancestors.atomic",
1061 $org_unit, $depth );
1062 return $U->build_org_tree($orglist);
1066 __PACKAGE__->register_method(
1067 method => "get_standings",
1068 api_name => "open-ils.actor.standings.retrieve"
1073 return $user_standings if $user_standings;
1074 return $user_standings =
1075 $apputils->simple_scalar_request(
1077 "open-ils.cstore.direct.config.standing.search.atomic",
1078 { id => { "!=" => undef } }
1084 __PACKAGE__->register_method(
1085 method => "get_my_org_path",
1086 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1089 sub get_my_org_path {
1090 my( $self, $client, $auth, $org_id ) = @_;
1091 my $e = new_editor(authtoken=>$auth);
1092 return $e->event unless $e->checkauth;
1093 $org_id = $e->requestor->ws_ou unless defined $org_id;
1095 return $apputils->simple_scalar_request(
1097 "open-ils.storage.actor.org_unit.full_path.atomic",
1102 __PACKAGE__->register_method(
1103 method => "patron_adv_search",
1104 api_name => "open-ils.actor.patron.search.advanced" );
1105 sub patron_adv_search {
1106 my( $self, $client, $auth, $search_hash,
1107 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1109 my $e = new_editor(authtoken=>$auth);
1110 return $e->event unless $e->checkauth;
1111 return $e->event unless $e->allowed('VIEW_USER');
1112 return $U->storagereq(
1113 "open-ils.storage.actor.user.crazy_search", $search_hash,
1114 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1118 __PACKAGE__->register_method(
1119 method => "update_passwd",
1121 api_name => "open-ils.actor.user.password.update");
1123 __PACKAGE__->register_method(
1124 method => "update_passwd",
1125 api_name => "open-ils.actor.user.username.update");
1127 __PACKAGE__->register_method(
1128 method => "update_passwd",
1129 api_name => "open-ils.actor.user.email.update");
1132 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1133 my $e = new_editor(xact=>1, authtoken=>$auth);
1134 return $e->die_event unless $e->checkauth;
1136 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1137 or return $e->die_event;
1138 my $api = $self->api_name;
1140 if( $api =~ /password/o ) {
1142 # make sure the original password matches the in-database password
1143 return OpenILS::Event->new('INCORRECT_PASSWORD')
1144 if md5_hex($orig_pw) ne $db_user->passwd;
1145 $db_user->passwd($new_val);
1149 # if we don't clear the password, the user will be updated with
1150 # a hashed version of the hashed version of their password
1151 $db_user->clear_passwd;
1153 if( $api =~ /username/o ) {
1155 # make sure no one else has this username
1156 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1157 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1158 $db_user->usrname($new_val);
1160 } elsif( $api =~ /email/o ) {
1161 $db_user->email($new_val);
1165 $e->update_actor_user($db_user) or return $e->die_event;
1173 __PACKAGE__->register_method(
1174 method => "check_user_perms",
1175 api_name => "open-ils.actor.user.perm.check",
1176 notes => <<" NOTES");
1177 Takes a login session, user id, an org id, and an array of perm type strings. For each
1178 perm type, if the user does *not* have the given permission it is added
1179 to a list which is returned from the method. If all permissions
1180 are allowed, an empty list is returned
1181 if the logged in user does not match 'user_id', then the logged in user must
1182 have VIEW_PERMISSION priveleges.
1185 sub check_user_perms {
1186 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1188 my( $staff, $evt ) = $apputils->checkses($login_session);
1189 return $evt if $evt;
1191 if($staff->id ne $user_id) {
1192 if( $evt = $apputils->check_perms(
1193 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1199 for my $perm (@$perm_types) {
1200 if($apputils->check_perms($user_id, $org_id, $perm)) {
1201 push @not_allowed, $perm;
1205 return \@not_allowed
1208 __PACKAGE__->register_method(
1209 method => "check_user_perms2",
1210 api_name => "open-ils.actor.user.perm.check.multi_org",
1212 Checks the permissions on a list of perms and orgs for a user
1213 @param authtoken The login session key
1214 @param user_id The id of the user to check
1215 @param orgs The array of org ids
1216 @param perms The array of permission names
1217 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1218 if the logged in user does not match 'user_id', then the logged in user must
1219 have VIEW_PERMISSION priveleges.
1222 sub check_user_perms2 {
1223 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1225 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1226 $authtoken, $user_id, 'VIEW_PERMISSION' );
1227 return $evt if $evt;
1230 for my $org (@$orgs) {
1231 for my $perm (@$perms) {
1232 if($apputils->check_perms($user_id, $org, $perm)) {
1233 push @not_allowed, [ $org, $perm ];
1238 return \@not_allowed
1242 __PACKAGE__->register_method(
1243 method => 'check_user_perms3',
1244 api_name => 'open-ils.actor.user.perm.highest_org',
1246 Returns the highest org unit id at which a user has a given permission
1247 If the requestor does not match the target user, the requestor must have
1248 'VIEW_PERMISSION' rights at the home org unit of the target user
1249 @param authtoken The login session key
1250 @param userid The id of the user in question
1251 @param perm The permission to check
1252 @return The org unit highest in the org tree within which the user has
1253 the requested permission
1256 sub check_user_perms3 {
1257 my($self, $client, $authtoken, $user_id, $perm) = @_;
1258 my $e = new_editor(authtoken=>$authtoken);
1259 return $e->event unless $e->checkauth;
1261 my $tree = $U->get_org_tree();
1263 unless($e->requestor->id == $user_id) {
1264 my $user = $e->retrieve_actor_user($user_id)
1265 or return $e->event;
1266 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1267 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1270 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1274 __PACKAGE__->register_method(
1275 method => 'check_user_work_perms',
1276 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1280 Returns a set of org units which represent the highest orgs in
1281 the org tree where the user has the requested permission. The
1282 purpose of this method is to return the smallest set of org units
1283 which represent the full expanse of the user's ability to perform
1284 the requested action. The user whose perms this method should
1285 check is implied by the authtoken. /,
1287 {desc => 'authtoken', type => 'string'},
1288 {desc => 'permission name', type => 'string'},
1289 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1291 return => {desc => 'An array of org IDs'}
1295 __PACKAGE__->register_method(
1296 method => 'check_user_work_perms',
1297 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1300 @see open-ils.actor.user.work_perm.highest_org_set
1301 Returns a list of org trees. The root of each tree
1302 is the highest org in the organization hierarchy where the user has the
1303 requested permission. Below each tree root is its full tree of descendants.
1307 __PACKAGE__->register_method(
1308 method => 'check_user_work_perms',
1309 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1312 @see open-ils.actor.user.work_perm.highest_org_set
1313 Returns a list of list of all of the org_units where the user
1314 has the requested permission. The first item in each list
1315 is the highest permission org for that section of the
1316 org tree. The remaining items in each sub-list are the
1317 descendants of that org.
1322 __PACKAGE__->register_method(
1323 method => 'check_user_work_perms',
1324 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1327 @see open-ils.actor.user.work_perm.highest_org_set
1328 Returns a list of lists of all of the org_unit IDs where the user
1329 has the requested permission. The first item in each list
1330 is the highest permission org for that section of the
1331 org tree. The remaining items in each sub-list are the
1332 descendants of that org.
1336 __PACKAGE__->register_method(
1337 method => 'check_user_work_perms_batch',
1338 api_name => 'open-ils.actor.user.work_perm.highest_org_set.batch',
1341 __PACKAGE__->register_method(
1342 method => 'check_user_work_perms_batch',
1343 api_name => 'open-ils.actor.user.work_perm.org_tree_list.batch',
1346 __PACKAGE__->register_method(
1347 method => 'check_user_work_perms_batch',
1348 api_name => 'open-ils.actor.user.work_perm.org_unit_list.batch',
1351 __PACKAGE__->register_method(
1352 method => 'check_user_work_perms_batch',
1353 api_name => 'open-ils.actor.user.work_perm.org_id_list.batch',
1358 sub check_user_work_perms {
1359 my($self, $conn, $auth, $perm, $options) = @_;
1360 my $e = new_editor(authtoken=>$auth);
1361 return $e->event unless $e->checkauth;
1362 return check_user_work_perms_impl($self, $conn, $e, $perm, $options);
1365 sub check_user_work_perms_batch {
1366 my($self, $conn, $auth, $perm_list, $options) = @_;
1367 my $e = new_editor(authtoken=>$auth);
1368 return $e->event unless $e->checkauth;
1370 $map->{$_} = check_user_work_perms_impl($self, $conn, $e, $_, $options) for @$perm_list;
1374 sub check_user_work_perms_impl {
1375 my($self, $conn, $e, $perm, $options) = @_;
1376 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1378 return $orglist if $self->api_name =~ /highest_org_set/;
1380 # build a list of org trees
1381 return get_org_descendants($self, $conn, $orglist)
1382 if $self->api_name =~ /org_tree_list/;
1385 for my $orgid (@$orglist) {
1386 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1387 unshift @sublist, $orgid; # make sure it's at the front of the list
1388 if($self->api_name =~ /org_id_list/) {
1389 push(@list, @sublist);
1391 push(@list, @{$e->batch_retrieve_actor_org_unit(\@sublist)});
1399 __PACKAGE__->register_method(
1400 method => 'check_user_perms4',
1401 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1403 Returns the highest org unit id at which a user has a given permission
1404 If the requestor does not match the target user, the requestor must have
1405 'VIEW_PERMISSION' rights at the home org unit of the target user
1406 @param authtoken The login session key
1407 @param userid The id of the user in question
1408 @param perms An array of perm names to check
1409 @return An array of orgId's representing the org unit
1410 highest in the org tree within which the user has the requested permission
1411 The arrah of orgId's has matches the order of the perms array
1414 sub check_user_perms4 {
1415 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1417 my( $staff, $target, $org, $evt );
1419 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1420 $authtoken, $userid, 'VIEW_PERMISSION' );
1421 return $evt if $evt;
1424 return [] unless ref($perms);
1425 my $tree = $U->get_org_tree();
1427 for my $p (@$perms) {
1428 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1436 __PACKAGE__->register_method(
1437 method => "user_fines_summary",
1438 api_name => "open-ils.actor.user.fines.summary",
1440 notes => <<" NOTES");
1441 Returns a short summary of the users total open fines, excluding voided fines
1442 Params are login_session, user_id
1443 Returns a 'mous' object.
1446 sub user_fines_summary {
1447 my( $self, $client, $auth, $user_id ) = @_;
1448 my $e = new_editor(authtoken=>$auth);
1449 return $e->event unless $e->checkauth;
1450 my $user = $e->retrieve_actor_user($user_id)
1451 or return $e->event;
1453 if( $user_id ne $e->requestor->id ) {
1454 return $e->event unless
1455 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1458 # run this inside a transaction to prevent replication delay errors
1459 my $ses = $U->start_db_session();
1460 my $s = $ses->request(
1461 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1462 $U->rollback_db_session($ses);
1469 __PACKAGE__->register_method(
1470 method => "user_transactions",
1471 api_name => "open-ils.actor.user.transactions",
1472 notes => <<" NOTES");
1473 Returns a list of open user transactions (mbts objects);
1474 Params are login_session, user_id
1475 Optional third parameter is the transactions type. defaults to all
1478 __PACKAGE__->register_method(
1479 method => "user_transactions",
1480 api_name => "open-ils.actor.user.transactions.have_charge",
1481 notes => <<" NOTES");
1482 Returns a list of all open user transactions (mbts objects) that have an initial charge
1483 Params are login_session, user_id
1484 Optional third parameter is the transactions type. defaults to all
1487 __PACKAGE__->register_method(
1488 method => "user_transactions",
1489 api_name => "open-ils.actor.user.transactions.have_balance",
1490 notes => <<" NOTES");
1491 Returns a list of all open user transactions (mbts objects) that have a balance
1492 Params are login_session, user_id
1493 Optional third parameter is the transactions type. defaults to all
1496 __PACKAGE__->register_method(
1497 method => "user_transactions",
1498 api_name => "open-ils.actor.user.transactions.fleshed",
1499 notes => <<" NOTES");
1500 Returns an object/hash of transaction, circ, title where transaction = an open
1501 user transactions (mbts objects), circ is the attached circluation, and title
1502 is the title the circ points to
1503 Params are login_session, user_id
1504 Optional third parameter is the transactions type. defaults to all
1507 __PACKAGE__->register_method(
1508 method => "user_transactions",
1509 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1510 notes => <<" NOTES");
1511 Returns an object/hash of transaction, circ, title where transaction = an open
1512 user transactions that has an initial charge (mbts objects), circ is the
1513 attached circluation, and title is the title the circ points to
1514 Params are login_session, user_id
1515 Optional third parameter is the transactions type. defaults to all
1518 __PACKAGE__->register_method(
1519 method => "user_transactions",
1520 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1521 notes => <<" NOTES");
1522 Returns an object/hash of transaction, circ, title where transaction = an open
1523 user transaction that has a balance (mbts objects), circ is the attached
1524 circluation, and title is the title the circ points to
1525 Params are login_session, user_id
1526 Optional third parameter is the transaction type. defaults to all
1529 __PACKAGE__->register_method(
1530 method => "user_transactions",
1531 api_name => "open-ils.actor.user.transactions.count",
1532 notes => <<" NOTES");
1533 Returns an object/hash of transaction, circ, title where transaction = an open
1534 user transactions (mbts objects), circ is the attached circluation, and title
1535 is the title the circ points to
1536 Params are login_session, user_id
1537 Optional third parameter is the transactions type. defaults to all
1540 __PACKAGE__->register_method(
1541 method => "user_transactions",
1542 api_name => "open-ils.actor.user.transactions.have_charge.count",
1543 notes => <<" NOTES");
1544 Returns an object/hash of transaction, circ, title where transaction = an open
1545 user transactions that has an initial charge (mbts objects), circ is the
1546 attached circluation, and title is the title the circ points to
1547 Params are login_session, user_id
1548 Optional third parameter is the transactions type. defaults to all
1551 __PACKAGE__->register_method(
1552 method => "user_transactions",
1553 api_name => "open-ils.actor.user.transactions.have_balance.count",
1554 notes => <<" NOTES");
1555 Returns an object/hash of transaction, circ, title where transaction = an open
1556 user transaction that has a balance (mbts objects), circ is the attached
1557 circluation, and title is the title the circ points to
1558 Params are login_session, user_id
1559 Optional third parameter is the transaction type. defaults to all
1562 __PACKAGE__->register_method(
1563 method => "user_transactions",
1564 api_name => "open-ils.actor.user.transactions.have_balance.total",
1565 notes => <<" NOTES");
1566 Returns an object/hash of transaction, circ, title where transaction = an open
1567 user transaction that has a balance (mbts objects), circ is the attached
1568 circluation, and title is the title the circ points to
1569 Params are login_session, user_id
1570 Optional third parameter is the transaction type. defaults to all
1575 sub user_transactions {
1576 my( $self, $client, $login_session, $user_id, $type ) = @_;
1578 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1579 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1580 return $evt if $evt;
1582 my $api = $self->api_name();
1586 if(defined($type)) { @xact = (xact_type => $type);
1588 } else { @xact = (); }
1591 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1592 ->run($login_session => $user_id => $type);
1594 if($api =~ /have_charge/o) {
1596 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1598 } elsif($api =~ /have_balance/o) {
1600 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1603 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1607 if($api =~ /total/o) {
1609 for my $t (@$trans) {
1610 $total += $t->balance_owed;
1613 $logger->debug("Total balance owed by user $user_id: $total");
1617 if($api =~ /count/o) { return scalar @$trans; }
1618 if($api !~ /fleshed/o) { return $trans; }
1621 for my $t (@$trans) {
1623 if( $t->xact_type ne 'circulation' ) {
1624 push @resp, {transaction => $t};
1628 my $circ = $apputils->simple_scalar_request(
1630 "open-ils.cstore.direct.action.circulation.retrieve",
1635 my $title = $apputils->simple_scalar_request(
1637 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1638 $circ->target_copy );
1642 my $u = OpenILS::Utils::ModsParser->new();
1643 $u->start_mods_batch($title->marc());
1644 my $mods = $u->finish_mods_batch();
1645 $mods->doc_id($title->id) if $mods;
1647 push @resp, {transaction => $t, circ => $circ, record => $mods };
1655 __PACKAGE__->register_method(
1656 method => "user_transaction_retrieve",
1657 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1659 notes => <<" NOTES");
1660 Returns a fleshedtransaction record
1662 __PACKAGE__->register_method(
1663 method => "user_transaction_retrieve",
1664 api_name => "open-ils.actor.user.transaction.retrieve",
1666 notes => <<" NOTES");
1667 Returns a transaction record
1669 sub user_transaction_retrieve {
1670 my( $self, $client, $login_session, $bill_id ) = @_;
1672 # XXX I think I'm deprecated... make sure
1674 my $trans = $apputils->simple_scalar_request(
1676 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1680 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1681 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1682 return $evt if $evt;
1684 my $api = $self->api_name();
1685 if($api !~ /fleshed/o) { return $trans; }
1687 if( $trans->xact_type ne 'circulation' ) {
1688 $logger->debug("Returning non-circ transaction");
1689 return {transaction => $trans};
1692 my $circ = $apputils->simple_scalar_request(
1694 "open-ils..direct.action.circulation.retrieve",
1697 return {transaction => $trans} unless $circ;
1698 $logger->debug("Found the circ transaction");
1700 my $title = $apputils->simple_scalar_request(
1702 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1703 $circ->target_copy );
1705 return {transaction => $trans, circ => $circ } unless $title;
1706 $logger->debug("Found the circ title");
1710 my $u = OpenILS::Utils::ModsParser->new();
1711 $u->start_mods_batch($title->marc());
1712 $mods = $u->finish_mods_batch();
1714 if ($title->id == OILS_PRECAT_RECORD) {
1715 my $copy = $apputils->simple_scalar_request(
1717 "open-ils.cstore.direct.asset.copy.retrieve",
1718 $circ->target_copy );
1720 $mods = new Fieldmapper::metabib::virtual_record;
1721 $mods->doc_id(OILS_PRECAT_RECORD);
1722 $mods->title($copy->dummy_title);
1723 $mods->author($copy->dummy_author);
1727 $logger->debug("MODSized the circ title");
1729 return {transaction => $trans, circ => $circ, record => $mods };
1733 __PACKAGE__->register_method(
1734 method => "hold_request_count",
1735 api_name => "open-ils.actor.user.hold_requests.count",
1738 notes => <<" NOTES");
1739 Returns hold ready/total counts
1741 sub hold_request_count {
1742 my( $self, $client, $login_session, $userid ) = @_;
1744 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1745 $login_session, $userid, 'VIEW_HOLD' );
1746 return $evt if $evt;
1749 my $holds = $apputils->simple_scalar_request(
1751 "open-ils.cstore.direct.action.hold_request.search.atomic",
1754 fulfillment_time => {"=" => undef },
1755 cancel_time => undef,
1760 for my $h (@$holds) {
1761 next unless $h->capture_time and $h->current_copy;
1763 my $copy = $apputils->simple_scalar_request(
1765 "open-ils.cstore.direct.asset.copy.retrieve",
1769 if ($copy and $copy->status == 8) {
1774 return { total => scalar(@$holds), ready => scalar(@ready) };
1778 __PACKAGE__->register_method(
1779 method => "checkedout_count",
1780 api_name => "open-ils.actor.user.checked_out.count__",
1782 notes => <<" NOTES");
1783 Returns a transaction record
1787 sub checkedout_count {
1788 my( $self, $client, $login_session, $userid ) = @_;
1790 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1791 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1792 return $evt if $evt;
1794 my $circs = $apputils->simple_scalar_request(
1796 "open-ils.cstore.direct.action.circulation.search.atomic",
1797 { usr => $userid, stop_fines => undef }
1798 #{ usr => $userid, checkin_time => {"=" => undef } }
1801 my $parser = DateTime::Format::ISO8601->new;
1804 for my $c (@$circs) {
1805 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1806 my $due = $due_dt->epoch;
1808 if ($due < DateTime->today->epoch) {
1813 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1817 __PACKAGE__->register_method(
1818 method => "checked_out",
1819 api_name => "open-ils.actor.user.checked_out",
1823 Returns a structure of circulations objects sorted by
1824 out, overdue, lost, claims_returned, long_overdue.
1825 A list of IDs are returned of each type.
1826 lost, long_overdue, and claims_returned circ will not
1827 be "finished" (there is an outstanding balance or some
1828 other pending action on the circ).
1830 The .count method also includes a 'total' field which
1831 sums all "open" circs
1835 __PACKAGE__->register_method(
1836 method => "checked_out",
1837 api_name => "open-ils.actor.user.checked_out.count",
1840 signature => q/@see open-ils.actor.user.checked_out/
1844 my( $self, $conn, $auth, $userid ) = @_;
1846 my $e = new_editor(authtoken=>$auth);
1847 return $e->event unless $e->checkauth;
1849 if( $userid ne $e->requestor->id ) {
1850 my $user = $e->retrieve_actor_user($userid) or return $e->event;
1851 unless($e->allowed('VIEW_CIRCULATIONS', $user->home_ou)) {
1853 # see if there is a friend link allowing circ.view perms
1854 my $allowed = OpenILS::Application::Actor::Friends->friend_perm_allowed(
1855 $e, $userid, $e->requestor->id, 'circ.view');
1856 return $e->event unless $allowed;
1860 my $count = $self->api_name =~ /count/;
1861 return _checked_out( $count, $e, $userid );
1865 my( $iscount, $e, $userid ) = @_;
1866 my $meth = 'open-ils.storage.actor.user.checked_out';
1867 $meth = "$meth.count" if $iscount;
1868 return $U->storagereq($meth, $userid);
1872 sub _checked_out_WHAT {
1873 my( $iscount, $e, $userid ) = @_;
1875 my $circs = $e->search_action_circulation(
1876 { usr => $userid, stop_fines => undef });
1878 my $mcircs = $e->search_action_circulation(
1881 checkin_time => undef,
1882 xact_finish => undef,
1886 push( @$circs, @$mcircs );
1888 my $parser = DateTime::Format::ISO8601->new;
1890 # split the circs up into overdue and not-overdue circs
1892 for my $c (@$circs) {
1893 if( $c->due_date ) {
1894 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1895 my $due = $due_dt->epoch;
1896 if ($due < DateTime->today->epoch) {
1897 push @overdue, $c->id;
1906 # grab all of the lost, claims-returned, and longoverdue circs
1907 #my $open = $e->search_action_circulation(
1908 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1911 # these items have stop_fines, but no xact_finish, so money
1912 # is owed on them and they have not been checked in
1913 my $open = $e->search_action_circulation(
1916 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1917 xact_finish => undef,
1918 checkin_time => undef,
1923 my( @lost, @cr, @lo );
1924 for my $c (@$open) {
1925 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1926 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1927 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1933 total => @$circs + @lost + @cr + @lo,
1934 out => scalar(@out),
1935 overdue => scalar(@overdue),
1936 lost => scalar(@lost),
1937 claims_returned => scalar(@cr),
1938 long_overdue => scalar(@lo)
1944 overdue => \@overdue,
1946 claims_returned => \@cr,
1947 long_overdue => \@lo
1953 __PACKAGE__->register_method(
1954 method => "checked_in_with_fines",
1955 api_name => "open-ils.actor.user.checked_in_with_fines",
1958 signature => q/@see open-ils.actor.user.checked_out/
1960 sub checked_in_with_fines {
1961 my( $self, $conn, $auth, $userid ) = @_;
1963 my $e = new_editor(authtoken=>$auth);
1964 return $e->event unless $e->checkauth;
1966 if( $userid ne $e->requestor->id ) {
1967 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1970 # money is owed on these items and they are checked in
1971 my $open = $e->search_action_circulation(
1974 xact_finish => undef,
1975 checkin_time => { "!=" => undef },
1980 my( @lost, @cr, @lo );
1981 for my $c (@$open) {
1982 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1983 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1984 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1989 claims_returned => \@cr,
1990 long_overdue => \@lo
2002 __PACKAGE__->register_method(
2003 method => "user_transaction_history",
2004 api_name => "open-ils.actor.user.transactions.history",
2006 notes => <<" NOTES");
2007 Returns a list of billable transaction ids for a user, optionally by type
2009 __PACKAGE__->register_method(
2010 method => "user_transaction_history",
2011 api_name => "open-ils.actor.user.transactions.history.have_charge",
2013 notes => <<" NOTES");
2014 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2016 __PACKAGE__->register_method(
2017 method => "user_transaction_history",
2018 api_name => "open-ils.actor.user.transactions.history.have_balance",
2021 notes => <<" NOTES");
2022 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2024 __PACKAGE__->register_method(
2025 method => "user_transaction_history",
2026 api_name => "open-ils.actor.user.transactions.history.still_open",
2028 notes => <<" NOTES");
2029 Returns a list of billable transaction ids for a user that are not finished
2031 __PACKAGE__->register_method(
2032 method => "user_transaction_history",
2033 api_name => "open-ils.actor.user.transactions.history.have_bill",
2036 notes => <<" NOTES");
2037 Returns a list of billable transaction ids for a user that has billings
2040 sub user_transaction_history {
2041 my( $self, $conn, $auth, $userid, $type ) = @_;
2043 # run inside of a transaction to prevent replication delays
2044 my $e = new_editor(xact=>1, authtoken=>$auth);
2045 return $e->die_event unless $e->checkauth;
2047 if( $e->requestor->id ne $userid ) {
2048 return $e->die_event
2049 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2052 my $api = $self->api_name;
2053 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2055 my @xacts = @{ $e->search_money_billable_transaction(
2056 [ { usr => $userid, @xact_finish },
2058 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2059 order_by => { mbt => 'xact_start DESC' },
2067 #my @mbts = _make_mbts( @xacts );
2068 my @mbts = $U->make_mbts( @xacts );
2070 if(defined($type)) {
2071 @mbts = grep { $_->xact_type eq $type } @mbts;
2074 if($api =~ /have_balance/o) {
2075 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2078 if($api =~ /have_charge/o) {
2079 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2082 if($api =~ /have_bill/o) {
2083 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2091 __PACKAGE__->register_method(
2092 method => "user_perms",
2093 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2095 notes => <<" NOTES");
2096 Returns a list of permissions
2099 my( $self, $client, $authtoken, $user ) = @_;
2101 my( $staff, $evt ) = $apputils->checkses($authtoken);
2102 return $evt if $evt;
2104 $user ||= $staff->id;
2106 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2110 return $apputils->simple_scalar_request(
2112 "open-ils.storage.permission.user_perms.atomic",
2116 __PACKAGE__->register_method(
2117 method => "retrieve_perms",
2118 api_name => "open-ils.actor.permissions.retrieve",
2119 notes => <<" NOTES");
2120 Returns a list of permissions
2122 sub retrieve_perms {
2123 my( $self, $client ) = @_;
2124 return $apputils->simple_scalar_request(
2126 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2127 { id => { '!=' => undef } }
2131 __PACKAGE__->register_method(
2132 method => "retrieve_groups",
2133 api_name => "open-ils.actor.groups.retrieve",
2134 notes => <<" NOTES");
2135 Returns a list of user groupss
2137 sub retrieve_groups {
2138 my( $self, $client ) = @_;
2139 return new_editor()->retrieve_all_permission_grp_tree();
2142 __PACKAGE__->register_method(
2143 method => "retrieve_org_address",
2144 api_name => "open-ils.actor.org_unit.address.retrieve",
2145 notes => <<' NOTES');
2146 Returns an org_unit address by ID
2147 @param An org_address ID
2149 sub retrieve_org_address {
2150 my( $self, $client, $id ) = @_;
2151 return $apputils->simple_scalar_request(
2153 "open-ils.cstore.direct.actor.org_address.retrieve",
2158 __PACKAGE__->register_method(
2159 method => "retrieve_groups_tree",
2160 api_name => "open-ils.actor.groups.tree.retrieve",
2161 notes => <<" NOTES");
2162 Returns a list of user groups
2164 sub retrieve_groups_tree {
2165 my( $self, $client ) = @_;
2166 return new_editor()->search_permission_grp_tree(
2171 flesh_fields => { pgt => ["children"] },
2172 order_by => { pgt => 'name'}
2179 __PACKAGE__->register_method(
2180 method => "add_user_to_groups",
2181 api_name => "open-ils.actor.user.set_groups",
2182 notes => <<" NOTES");
2183 Adds a user to one or more permission groups
2186 sub add_user_to_groups {
2187 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2189 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2190 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2191 return $evt if $evt;
2193 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2194 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2195 return $evt if $evt;
2197 $apputils->simplereq(
2199 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2201 for my $group (@$groups) {
2202 my $link = Fieldmapper::permission::usr_grp_map->new;
2204 $link->usr($userid);
2206 my $id = $apputils->simplereq(
2208 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2214 __PACKAGE__->register_method(
2215 method => "get_user_perm_groups",
2216 api_name => "open-ils.actor.user.get_groups",
2217 notes => <<" NOTES");
2218 Retrieve a user's permission groups.
2222 sub get_user_perm_groups {
2223 my( $self, $client, $authtoken, $userid ) = @_;
2225 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2226 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2227 return $evt if $evt;
2229 return $apputils->simplereq(
2231 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2235 __PACKAGE__->register_method(
2236 method => "get_user_work_ous",
2237 api_name => "open-ils.actor.user.get_work_ous",
2238 notes => <<" NOTES");
2239 Retrieve a user's work org units.
2241 __PACKAGE__->register_method(
2242 method => "get_user_work_ous",
2243 api_name => "open-ils.actor.user.get_work_ous.ids",
2244 notes => <<" NOTES");
2245 Retrieve a user's work org units.
2249 sub get_user_work_ous {
2250 my( $self, $client, $auth, $userid ) = @_;
2251 my $e = new_editor(authtoken=>$auth);
2252 return $e->event unless $e->checkauth;
2253 $userid ||= $e->requestor->id;
2255 if($e->requestor->id != $userid) {
2256 my $user = $e->retrieve_actor_user($userid)
2257 or return $e->event;
2258 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2261 return $e->search_permission_usr_work_ou_map({usr => $userid})
2262 unless $self->api_name =~ /.ids$/;
2264 # client just wants a list of org IDs
2265 return $U->get_user_work_ou_ids($e, $userid);
2271 __PACKAGE__->register_method (
2272 method => 'register_workstation',
2273 api_name => 'open-ils.actor.workstation.register.override',
2274 signature => q/@see open-ils.actor.workstation.register/);
2276 __PACKAGE__->register_method (
2277 method => 'register_workstation',
2278 api_name => 'open-ils.actor.workstation.register',
2280 Registers a new workstion in the system
2281 @param authtoken The login session key
2282 @param name The name of the workstation id
2283 @param owner The org unit that owns this workstation
2284 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2285 if the name is already in use.
2288 sub register_workstation {
2289 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2291 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2292 return $e->die_event unless $e->checkauth;
2293 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2294 my $existing = $e->search_actor_workstation({name => $name})->[0];
2298 if( $self->api_name =~ /override/o ) {
2299 # workstation with the given name exists.
2301 if($owner ne $existing->owning_lib) {
2302 # if necessary, update the owning_lib of the workstation
2304 $logger->info("changing owning lib of workstation ".$existing->id.
2305 " from ".$existing->owning_lib." to $owner");
2306 return $e->die_event unless
2307 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2309 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2311 $existing->owning_lib($owner);
2312 return $e->die_event unless $e->update_actor_workstation($existing);
2318 "attempt to register an existing workstation. returning existing ID");
2321 return $existing->id;
2324 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2328 my $ws = Fieldmapper::actor::workstation->new;
2329 $ws->owning_lib($owner);
2331 $e->create_actor_workstation($ws) or return $e->die_event;
2333 return $ws->id; # note: editor sets the id on the new object for us
2336 __PACKAGE__->register_method (
2337 method => 'workstation_list',
2338 api_name => 'open-ils.actor.workstation.list',
2340 Returns a list of workstations registered at the given location
2341 @param authtoken The login session key
2342 @param ids A list of org_unit.id's for the workstation owners
2345 sub workstation_list {
2346 my( $self, $conn, $authtoken, @orgs ) = @_;
2348 my $e = new_editor(authtoken=>$authtoken);
2349 return $e->event unless $e->checkauth;
2354 unless $e->allowed('REGISTER_WORKSTATION', $o);
2355 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2366 __PACKAGE__->register_method (
2367 method => 'fetch_patron_note',
2368 api_name => 'open-ils.actor.note.retrieve.all',
2371 Returns a list of notes for a given user
2372 Requestor must have VIEW_USER permission if pub==false and
2373 @param authtoken The login session key
2374 @param args Hash of params including
2375 patronid : the patron's id
2376 pub : true if retrieving only public notes
2380 sub fetch_patron_note {
2381 my( $self, $conn, $authtoken, $args ) = @_;
2382 my $patronid = $$args{patronid};
2384 my($reqr, $evt) = $U->checkses($authtoken);
2385 return $evt if $evt;
2388 ($patron, $evt) = $U->fetch_user($patronid);
2389 return $evt if $evt;
2392 if( $patronid ne $reqr->id ) {
2393 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2394 return $evt if $evt;
2396 return $U->cstorereq(
2397 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2398 { usr => $patronid, pub => 't' } );
2401 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2402 return $evt if $evt;
2404 return $U->cstorereq(
2405 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2408 __PACKAGE__->register_method (
2409 method => 'create_user_note',
2410 api_name => 'open-ils.actor.note.create',
2412 Creates a new note for the given user
2413 @param authtoken The login session key
2414 @param note The note object
2417 sub create_user_note {
2418 my( $self, $conn, $authtoken, $note ) = @_;
2419 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2420 return $e->die_event unless $e->checkauth;
2422 my $user = $e->retrieve_actor_user($note->usr)
2423 or return $e->die_event;
2425 return $e->die_event unless
2426 $e->allowed('UPDATE_USER',$user->home_ou);
2428 $note->creator($e->requestor->id);
2429 $e->create_actor_usr_note($note) or return $e->die_event;
2435 __PACKAGE__->register_method (
2436 method => 'delete_user_note',
2437 api_name => 'open-ils.actor.note.delete',
2439 Deletes a note for the given user
2440 @param authtoken The login session key
2441 @param noteid The note id
2444 sub delete_user_note {
2445 my( $self, $conn, $authtoken, $noteid ) = @_;
2447 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2448 return $e->die_event unless $e->checkauth;
2449 my $note = $e->retrieve_actor_usr_note($noteid)
2450 or return $e->die_event;
2451 my $user = $e->retrieve_actor_user($note->usr)
2452 or return $e->die_event;
2453 return $e->die_event unless
2454 $e->allowed('UPDATE_USER', $user->home_ou);
2456 $e->delete_actor_usr_note($note) or return $e->die_event;
2462 __PACKAGE__->register_method (
2463 method => 'update_user_note',
2464 api_name => 'open-ils.actor.note.update',
2466 @param authtoken The login session key
2467 @param note The note
2471 sub update_user_note {
2472 my( $self, $conn, $auth, $note ) = @_;
2473 my $e = new_editor(authtoken=>$auth, xact=>1);
2474 return $e->event unless $e->checkauth;
2475 my $patron = $e->retrieve_actor_user($note->usr)
2476 or return $e->event;
2477 return $e->event unless
2478 $e->allowed('UPDATE_USER', $patron->home_ou);
2479 $e->update_actor_user_note($note)
2480 or return $e->event;
2488 __PACKAGE__->register_method (
2489 method => 'create_closed_date',
2490 api_name => 'open-ils.actor.org_unit.closed_date.create',
2492 Creates a new closing entry for the given org_unit
2493 @param authtoken The login session key
2494 @param note The closed_date object
2497 sub create_closed_date {
2498 my( $self, $conn, $authtoken, $cd ) = @_;
2500 my( $user, $evt ) = $U->checkses($authtoken);
2501 return $evt if $evt;
2503 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2504 return $evt if $evt;
2506 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2508 my $id = $U->storagereq(
2509 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2510 return $U->DB_UPDATE_FAILED($cd) unless $id;
2515 __PACKAGE__->register_method (
2516 method => 'delete_closed_date',
2517 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2519 Deletes a closing entry for the given org_unit
2520 @param authtoken The login session key
2521 @param noteid The close_date id
2524 sub delete_closed_date {
2525 my( $self, $conn, $authtoken, $cd ) = @_;
2527 my( $user, $evt ) = $U->checkses($authtoken);
2528 return $evt if $evt;
2531 ($cd_obj, $evt) = fetch_closed_date($cd);
2532 return $evt if $evt;
2534 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2535 return $evt if $evt;
2537 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2539 my $stat = $U->storagereq(
2540 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2541 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2546 __PACKAGE__->register_method(
2547 method => 'usrname_exists',
2548 api_name => 'open-ils.actor.username.exists',
2550 Returns 1 if the requested username exists, returns 0 otherwise
2554 sub usrname_exists {
2555 my( $self, $conn, $auth, $usrname ) = @_;
2556 my $e = new_editor(authtoken=>$auth);
2557 return $e->event unless $e->checkauth;
2558 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2559 return $$a[0] if $a and @$a;
2563 __PACKAGE__->register_method(
2564 method => 'barcode_exists',
2565 api_name => 'open-ils.actor.barcode.exists',
2568 Returns 1 if the requested barcode exists, returns 0 otherwise
2572 sub barcode_exists {
2573 my( $self, $conn, $auth, $barcode ) = @_;
2574 my $e = new_editor(authtoken=>$auth);
2575 return $e->event unless $e->checkauth;
2576 my $card = $e->search_actor_card({barcode => $barcode});
2582 #return undef unless @$card;
2583 #return $card->[0]->usr;
2587 __PACKAGE__->register_method(
2588 method => 'retrieve_net_levels',
2589 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2592 sub retrieve_net_levels {
2593 my( $self, $conn, $auth ) = @_;
2594 my $e = new_editor(authtoken=>$auth);
2595 return $e->event unless $e->checkauth;
2596 return $e->retrieve_all_config_net_access_level();
2600 __PACKAGE__->register_method(
2601 method => 'fetch_org_by_shortname',
2602 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2604 sub fetch_org_by_shortname {
2605 my( $self, $conn, $sname ) = @_;
2606 my $e = new_editor();
2607 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2608 return $e->event unless $org;
2613 __PACKAGE__->register_method(
2614 method => 'session_home_lib',
2615 api_name => 'open-ils.actor.session.home_lib',
2618 sub session_home_lib {
2619 my( $self, $conn, $auth ) = @_;
2620 my $e = new_editor(authtoken=>$auth);
2621 return undef unless $e->checkauth;
2622 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2623 return $org->shortname;
2626 __PACKAGE__->register_method(
2627 method => 'session_safe_token',
2628 api_name => 'open-ils.actor.session.safe_token',
2630 Returns a hashed session ID that is safe for export to the world.
2631 This safe token will expire after 1 hour of non-use.
2632 @param auth Active authentication token
2636 sub session_safe_token {
2637 my( $self, $conn, $auth ) = @_;
2638 my $e = new_editor(authtoken=>$auth);
2639 return undef unless $e->checkauth;
2641 my $safe_token = md5_hex($auth);
2643 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2645 # Add more like the following if needed...
2647 "safe-token-home_lib-shortname-$safe_token",
2648 $e->retrieve_actor_org_unit(
2649 $e->requestor->home_ou
2658 __PACKAGE__->register_method(
2659 method => 'safe_token_home_lib',
2660 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2662 Returns the home library shortname from the session
2663 asscociated with a safe token from generated by
2664 open-ils.actor.session.safe_token.
2665 @param safe_token Active safe token
2669 sub safe_token_home_lib {
2670 my( $self, $conn, $safe_token ) = @_;
2672 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2673 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2678 __PACKAGE__->register_method(
2679 method => 'slim_tree',
2680 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2683 my $tree = new_editor()->search_actor_org_unit(
2685 {"parent_ou" => undef },
2688 flesh_fields => { aou => ['children'] },
2689 order_by => { aou => 'name'},
2690 select => { aou => ["id","shortname", "name"]},
2695 return trim_tree($tree);
2701 return undef unless $tree;
2703 code => $tree->shortname,
2704 name => $tree->name,
2706 if( $tree->children and @{$tree->children} ) {
2707 $htree->{children} = [];
2708 for my $c (@{$tree->children}) {
2709 push( @{$htree->{children}}, trim_tree($c) );
2717 __PACKAGE__->register_method(
2718 method => "update_penalties",
2719 api_name => "open-ils.actor.user.penalties.update");
2721 sub update_penalties {
2722 my($self, $conn, $auth, $user_id) = @_;
2723 my $e = new_editor(authtoken=>$auth, xact => 1);
2724 return $e->die_event unless $e->checkauth;
2725 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2726 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2727 my $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $e->requestor->ws_ou);
2728 return $evt if $evt;
2734 __PACKAGE__->register_method(
2735 method => "apply_penalty",
2736 api_name => "open-ils.actor.user.penalty.apply");
2739 my($self, $conn, $auth, $penalty) = @_;
2740 my $e = new_editor(authtoken=>$auth, xact => 1);
2741 return $e->die_event unless $e->checkauth;
2742 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2743 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2745 # is it already applied?
2746 return 1 if $e->search_actor_user_standing_penalty(
2747 { usr => $penalty->usr,
2748 standing_penalty => $penalty->standing_penalty,
2749 org_unit => $penalty->org_unit
2752 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
2757 __PACKAGE__->register_method(
2758 method => "remove_penalty",
2759 api_name => "open-ils.actor.user.penalty.remove");
2761 sub remove_penalty {
2762 my($self, $conn, $auth, $penalty) = @_;
2763 my $e = new_editor(authtoken=>$auth, xact => 1);
2764 return $e->die_event unless $e->checkauth;
2765 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2766 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2768 $e->delete_actor_user_standing_penalty($penalty) or return $e->die_event;
2773 __PACKAGE__->register_method(
2774 method => "ranged_penalty_thresholds",
2775 api_name => "open-ils.actor.grp_penalty_threshold.ranged.retrieve",
2779 sub ranged_penalty_thresholds {
2780 my($self, $conn, $auth, $context_org) = @_;
2781 my $e = new_editor(authtoken=>$auth);
2782 return $e->event unless $e->checkauth;
2783 return $e->event unless $e->allowed('VIEW_GROUP_PENALTY_THRESHOLD', $context_org);
2784 my $list = $e->search_permission_grp_penalty_threshold([
2785 {org_unit => $U->get_org_ancestors($context_org)},
2786 {order_by => {pgpt => 'id'}}
2788 $conn->respond($_) for @$list;
2794 __PACKAGE__->register_method(
2795 method => "user_retrieve_fleshed_by_id",
2796 api_name => "open-ils.actor.user.fleshed.retrieve",);
2798 sub user_retrieve_fleshed_by_id {
2799 my( $self, $client, $auth, $user_id, $fields ) = @_;
2800 my $e = new_editor(authtoken => $auth);
2801 return $e->event unless $e->checkauth;
2803 if( $e->requestor->id != $user_id ) {
2804 return $e->event unless $e->allowed('VIEW_USER');
2810 "standing_penalties",
2814 "stat_cat_entries" ];
2815 return new_flesh_user($user_id, $fields, $e);
2819 sub new_flesh_user {
2822 my $fields = shift || [];
2825 my $fetch_penalties = 0;
2826 if(grep {$_ eq 'standing_penalties'} @$fields) {
2827 $fields = [grep {$_ ne 'standing_penalties'} @$fields];
2828 $fetch_penalties = 1;
2831 my $user = $e->retrieve_actor_user(
2836 "flesh_fields" => { "au" => $fields }
2839 ) or return $e->event;
2842 if( grep { $_ eq 'addresses' } @$fields ) {
2844 $user->addresses([]) unless @{$user->addresses};
2846 if( ref $user->billing_address ) {
2847 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2848 push( @{$user->addresses}, $user->billing_address );
2852 if( ref $user->mailing_address ) {
2853 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2854 push( @{$user->addresses}, $user->mailing_address );
2859 if($fetch_penalties) {
2860 # grab the user penalties ranged for this location
2861 $user->standing_penalties(
2862 $e->search_actor_user_standing_penalty([
2864 org_unit => $U->get_org_ancestors($e->requestor->ws_ou)
2867 flesh_fields => {ausp => ['standing_penalty']}
2874 $user->clear_passwd();
2881 __PACKAGE__->register_method(
2882 method => "user_retrieve_parts",
2883 api_name => "open-ils.actor.user.retrieve.parts",);
2885 sub user_retrieve_parts {
2886 my( $self, $client, $auth, $user_id, $fields ) = @_;
2887 my $e = new_editor(authtoken => $auth);
2888 return $e->event unless $e->checkauth;
2889 if( $e->requestor->id != $user_id ) {
2890 return $e->event unless $e->allowed('VIEW_USER');
2893 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2894 push(@resp, $user->$_()) for(@$fields);
2900 __PACKAGE__->register_method(
2901 method => 'user_opt_in_enabled',
2902 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2904 @return 1 if user opt-in is globally enabled, 0 otherwise.
2907 sub user_opt_in_enabled {
2908 my($self, $conn) = @_;
2909 my $sc = OpenSRF::Utils::SettingsClient->new;
2910 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2915 __PACKAGE__->register_method(
2916 method => 'user_opt_in_at_org',
2917 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2919 @param $auth The auth token
2920 @param user_id The ID of the user to test
2921 @return 1 if the user has opted in at the specified org,
2922 event on error, and 0 otherwise. /);
2923 sub user_opt_in_at_org {
2924 my($self, $conn, $auth, $user_id) = @_;
2926 # see if we even need to enforce the opt-in value
2927 return 1 unless user_opt_in_enabled($self);
2929 my $e = new_editor(authtoken => $auth);
2930 return $e->event unless $e->checkauth;
2931 my $org_id = $e->requestor->ws_ou;
2933 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2934 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2936 # user is automatically opted-in at the home org
2937 return 1 if $user->home_ou eq $org_id;
2939 my $vals = $e->search_actor_usr_org_unit_opt_in(
2940 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2946 __PACKAGE__->register_method(
2947 method => 'create_user_opt_in_at_org',
2948 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2950 @param $auth The auth token
2951 @param user_id The ID of the user to test
2952 @return The ID of the newly created object, event on error./);
2954 sub create_user_opt_in_at_org {
2955 my($self, $conn, $auth, $user_id) = @_;
2957 my $e = new_editor(authtoken => $auth, xact=>1);
2958 return $e->die_event unless $e->checkauth;
2959 my $org_id = $e->requestor->ws_ou;
2961 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2962 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2964 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2966 $opt_in->org_unit($org_id);
2967 $opt_in->usr($user_id);
2968 $opt_in->staff($e->requestor->id);
2969 $opt_in->opt_in_ts('now');
2970 $opt_in->opt_in_ws($e->requestor->wsid);
2972 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2973 or return $e->die_event;
2981 __PACKAGE__->register_method (
2982 method => 'retrieve_org_hours',
2983 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
2985 Returns the hours of operation for a specified org unit
2986 @param authtoken The login session key
2987 @param org_id The org_unit ID
2991 sub retrieve_org_hours {
2992 my($self, $conn, $auth, $org_id) = @_;
2993 my $e = new_editor(authtoken => $auth);
2994 return $e->die_event unless $e->checkauth;
2995 $org_id ||= $e->requestor->ws_ou;
2996 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);
3000 __PACKAGE__->register_method (
3001 method => 'verify_user_password',
3002 api_name => 'open-ils.actor.verify_user_password',
3004 Given a barcode or username and the MD5 encoded password,
3005 returns 1 if the password is correct. Returns 0 otherwise.
3009 sub verify_user_password {
3010 my($self, $conn, $auth, $barcode, $username, $password) = @_;
3011 my $e = new_editor(authtoken => $auth);
3012 return $e->die_event unless $e->checkauth;
3014 my $user_by_barcode;
3015 my $user_by_username;
3017 my $card = $e->search_actor_card([
3018 {barcode => $barcode},
3019 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return 0;
3020 $user_by_barcode = $card->usr;
3021 $user = $user_by_barcode;
3024 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return 0;
3025 $user = $user_by_username;
3027 return 0 if (!$user);
3028 return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3029 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3030 return 1 if $user->passwd eq $password;
3034 __PACKAGE__->register_method (
3035 method => 'retrieve_usr_id_via_barcode_or_usrname',
3036 api_name => "open-ils.actor.user.retrieve_id_by_barcode_or_username",
3038 Given a barcode or username returns the id for the user or
3043 sub retrieve_usr_id_via_barcode_or_usrname {
3044 my($self, $conn, $auth, $barcode, $username) = @_;
3045 my $e = new_editor(authtoken => $auth);
3046 return $e->die_event unless $e->checkauth;
3048 my $user_by_barcode;
3049 my $user_by_username;
3051 my $card = $e->search_actor_card([
3052 {barcode => $barcode},
3053 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
3054 $user_by_barcode = $card->usr;
3055 $user = $user_by_barcode;
3058 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
3060 $user = $user_by_username;
3062 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if (!$user);
3063 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3064 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3069 __PACKAGE__->register_method (
3070 method => 'merge_users',
3071 api_name => 'open-ils.actor.user.merge',
3074 Given a source user and destination user, transfer all data from the source
3075 to the dest. user and delete the source user. All user related data is
3076 transferred, including circulations, holds, bookbags, etc.
3082 my($self, $conn, $auth, $master_id, $options, @user_ids) = @_;
3083 my $e = new_editor(xact => 1, authtoken => $auth);
3084 return $e->die_event unless $e->checkauth;
3086 for my $src_id (@user_ids) {
3087 my $src_user = $e->retrieve_actor_user($src_id) or return $e->die_event;
3088 my $master_user = $e->retrieve_actor_user($master_id) or return $e->die_event;
3090 return $e->die_event unless $e->allowed('MERGE_USERS', $src_user->home_ou);
3091 if($src_user->home_ou ne $master_user->home_ou) {
3092 return $e->die_event unless $e->allowed('MERGE_USERS', $master_user->home_ou);
3095 return $e->die_event unless
3096 $e->json_query({from => ['actor.usr_merge', $src_id, $master_id]});
3105 __PACKAGE__->register_method (
3106 method => 'retrieve_friends',
3107 api_name => 'open-ils.actor.friends.retrieve',
3110 returns { confirmed: [], pending_out: [], pending_in: []}
3111 pending_out are users I'm requesting friendship with
3112 pending_in are users requesting friendship with me
3117 sub retrieve_friends {
3118 my($self, $conn, $auth, $user_id, $options) = @_;
3119 my $e = new_editor(authtoken => $auth);
3120 return $e->event unless $e->checkauth;
3121 $user_id ||= $e->requestor->id;
3123 if($user_id != $e->requestor->id) {
3124 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3125 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3128 return OpenILS::Application::Actor::Friends->retrieve_friends(
3129 $e, $user_id, $options);
3134 __PACKAGE__->register_method (
3135 method => 'apply_friend_perms',
3136 api_name => 'open-ils.actor.friends.perms.apply',
3142 sub apply_friend_perms {
3143 my($self, $conn, $auth, $user_id, $delegate_id, @perms) = @_;
3144 my $e = new_editor(authtoken => $auth, xact => 1);
3145 return $e->event unless $e->checkauth;
3147 if($user_id != $e->requestor->id) {
3148 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3149 return $e->die_event unless $e->allowed('VIEW_USER', $user->home_ou);
3152 for my $perm (@perms) {
3154 OpenILS::Application::Actor::Friends->apply_friend_perm(
3155 $e, $user_id, $delegate_id, $perm);
3156 return $evt if $evt;