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 my $all_allowed = $e->allowed("UPDATE_ORG_UNIT_SETTING_ALL", $org_id);
107 for my $name (keys %$settings) {
108 my $val = $$settings{$name};
109 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
111 unless($all_allowed) {
112 return $e->die_event unless $e->allowed("UPDATE_ORG_UNIT_SETTING.$name", $org_id);
116 $val = OpenSRF::Utils::JSON->perl2JSON($val);
119 $e->update_actor_org_unit_setting($set) or return $e->die_event;
121 $set = Fieldmapper::actor::org_unit_setting->new;
122 $set->org_unit($org_id);
125 $e->create_actor_org_unit_setting($set) or return $e->die_event;
128 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
136 my $fetch_user_settings;
137 my $fetch_ou_settings;
139 __PACKAGE__->register_method(
140 method => "user_settings",
141 api_name => "open-ils.actor.patron.settings.retrieve",
144 my( $self, $client, $auth, $user_id, $setting ) = @_;
146 my $e = new_editor(authtoken => $auth);
147 return $e->event unless $e->checkauth;
148 $user_id = $e->requestor->id unless defined $user_id;
150 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
151 if($e->requestor->id != $user_id) {
152 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
156 my $val = $e->search_actor_user_setting({usr => $user_id, name => $setting})->[0];
157 return '' unless $val;
158 return OpenSRF::Utils::JSON->JSON2perl($val->value);
160 my $s = $e->search_actor_user_setting({usr => $user_id});
161 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
167 __PACKAGE__->register_method(
168 method => "ou_settings",
169 api_name => "open-ils.actor.org_unit.settings.retrieve",
172 my( $self, $client, $ouid ) = @_;
174 $logger->info("Fetching org unit settings for org $ouid");
176 my $s = $apputils->simplereq(
178 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
180 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
184 __PACKAGE__->register_method(
185 method => "ranged_ou_settings",
186 api_name => "open-ils.actor.org_unit_setting.values.ranged.retrieve",
188 sub ranged_ou_settings {
189 my( $self, $client, $auth, $org_id ) = @_;
191 my $e = new_editor(authtoken => $auth);
192 return $e->event unless $e->checkauth;
193 return $e->event unless $e->allowed('VIEW_ORG_SETTINGS', $org_id);
196 my $org_list = $U->get_org_ancestors($org_id);
197 my $settings = $e->search_actor_org_unit_setting({org_unit => $org_list});
198 $org_list = [ reverse @$org_list ];
200 # start at the context org and capture the setting value
201 # without clobbering settings we've already captured
202 for my $org_id (@$org_list) {
204 my @sets = grep { $_->org_unit == $org_id } @$settings;
206 for my $set (@sets) {
207 $ranged_settings{$set->name} = OpenSRF::Utils::JSON->JSON2perl($set->value)
208 unless defined $ranged_settings{$set->name};
212 return \%ranged_settings;
217 __PACKAGE__->register_method(
218 api_name => 'open-ils.actor.ou_setting.ancestor_default',
219 method => 'ou_ancestor_setting',
222 # ------------------------------------------------------------------
223 # Attempts to find the org setting value for a given org. if not
224 # found at the requested org, searches up the org tree until it
225 # finds a parent that has the requested setting.
226 # when found, returns { org => $id, value => $value }
227 # otherwise, returns NULL
228 # ------------------------------------------------------------------
229 sub ou_ancestor_setting {
230 my( $self, $client, $orgid, $name ) = @_;
231 return $U->ou_ancestor_setting($orgid, $name);
234 __PACKAGE__->register_method(
235 api_name => 'open-ils.actor.ou_setting.ancestor_default.batch',
236 method => 'ou_ancestor_setting_batch',
238 sub ou_ancestor_setting_batch {
239 my( $self, $client, $orgid, $name_list ) = @_;
241 $values{$_} = $U->ou_ancestor_setting($orgid, $_) for @$name_list;
248 __PACKAGE__->register_method (
249 method => "ou_setting_delete",
250 api_name => 'open-ils.actor.org_setting.delete',
252 Deletes a specific org unit setting for a specific location
253 @param authtoken The login session key
254 @param orgid The org unit whose setting we're changing
255 @param setting The name of the setting to delete
256 @return True value on success.
260 sub ou_setting_delete {
261 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
262 my( $reqr, $evt) = $U->checkses($authtoken);
264 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
267 my $id = $U->cstorereq(
268 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
269 { name => $setting, org_unit => $orgid } );
271 $logger->debug("Retrieved setting $id in org unit setting delete");
273 my $s = $U->cstorereq(
274 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
276 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
290 __PACKAGE__->register_method(
291 method => "update_patron",
292 api_name => "open-ils.actor.patron.update",);
295 my( $self, $client, $user_session, $patron ) = @_;
297 my $session = $apputils->start_db_session();
301 $logger->info("Creating new patron...") if $patron->isnew;
302 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
304 my( $user_obj, $evt ) = $U->checkses($user_session);
307 $evt = check_group_perm($session, $user_obj, $patron);
311 # $new_patron is the patron in progress. $patron is the original patron
312 # passed in with the method. new_patron will change as the components
313 # of patron are added/updated.
317 # unflesh the real items on the patron
318 $patron->card( $patron->card->id ) if(ref($patron->card));
319 $patron->billing_address( $patron->billing_address->id )
320 if(ref($patron->billing_address));
321 $patron->mailing_address( $patron->mailing_address->id )
322 if(ref($patron->mailing_address));
324 # create/update the patron first so we can use his id
325 if($patron->isnew()) {
326 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
328 } else { $new_patron = $patron; }
330 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
333 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
336 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
339 # re-update the patron if anything has happened to him during this process
340 if($new_patron->ischanged()) {
341 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
345 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
348 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
351 $apputils->commit_db_session($session);
353 my $tses = OpenSRF::AppSession->create('open-ils.trigger');
355 $tses->request('open-ils.trigger.event.autocreate', 'au.create', $new_patron, $new_patron->home_ou);
357 $tses->request('open-ils.trigger.event.autocreate', 'au.update', $new_patron, $new_patron->home_ou);
360 return flesh_user($new_patron->id(), new_editor(requestor => $user_obj));
367 return new_flesh_user($id, [
370 "standing_penalties",
374 "stat_cat_entries" ], $e );
382 # clone and clear stuff that would break the database
386 my $new_patron = $patron->clone;
388 $new_patron->clear_billing_address();
389 $new_patron->clear_mailing_address();
390 $new_patron->clear_addresses();
391 $new_patron->clear_card();
392 $new_patron->clear_cards();
393 $new_patron->clear_id();
394 $new_patron->clear_isnew();
395 $new_patron->clear_ischanged();
396 $new_patron->clear_isdeleted();
397 $new_patron->clear_stat_cat_entries();
398 $new_patron->clear_permissions();
399 $new_patron->clear_standing_penalties();
409 my $user_obj = shift;
411 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
412 return (undef, $evt) if $evt;
414 my $ex = $session->request(
415 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
417 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
420 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
422 my $id = $session->request(
423 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
424 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
426 $logger->info("Successfully created new user [$id] in DB");
428 return ( $session->request(
429 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
433 sub check_group_perm {
434 my( $session, $requestor, $patron ) = @_;
437 # first let's see if the requestor has
438 # priveleges to update this user in any way
439 if( ! $patron->isnew ) {
440 my $p = $session->request(
441 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
443 # If we are the requestor (trying to update our own account)
444 # and we are not trying to change our profile, we're good
445 if( $p->id == $requestor->id and
446 $p->profile == $patron->profile ) {
451 $evt = group_perm_failed($session, $requestor, $p);
455 # They are allowed to edit this patron.. can they put the
456 # patron into the group requested?
457 $evt = group_perm_failed($session, $requestor, $patron);
463 sub group_perm_failed {
464 my( $session, $requestor, $patron ) = @_;
468 my $grpid = $patron->profile;
472 $logger->debug("user update looking for group perm for group $grpid");
473 $grp = $session->request(
474 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
475 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
477 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
479 $logger->info("user update checking perm $perm on user ".
480 $requestor->id." for update/create on user username=".$patron->usrname);
482 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
490 my( $session, $patron, $user_obj, $noperm) = @_;
492 $logger->info("Updating patron ".$patron->id." in DB");
497 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
498 return (undef, $evt) if $evt;
501 # update the password by itself to avoid the password protection magic
502 if( $patron->passwd ) {
503 my $s = $session->request(
504 'open-ils.storage.direct.actor.user.remote_update',
505 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
506 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
507 $patron->clear_passwd;
510 if(!$patron->ident_type) {
511 $patron->clear_ident_type;
512 $patron->clear_ident_value;
515 $evt = verify_last_xact($session, $patron);
516 return (undef, $evt) if $evt;
518 my $stat = $session->request(
519 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
520 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
525 sub verify_last_xact {
526 my( $session, $patron ) = @_;
527 return undef unless $patron->id and $patron->id > 0;
528 my $p = $session->request(
529 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
530 my $xact = $p->last_xact_id;
531 return undef unless $xact;
532 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
533 return OpenILS::Event->new('XACT_COLLISION')
534 if $xact != $patron->last_xact_id;
539 sub _check_dup_ident {
540 my( $session, $patron ) = @_;
542 return undef unless $patron->ident_value;
545 ident_type => $patron->ident_type,
546 ident_value => $patron->ident_value,
549 $logger->debug("patron update searching for dup ident values: " .
550 $patron->ident_type . ':' . $patron->ident_value);
552 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
554 my $dups = $session->request(
555 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
558 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
565 sub _add_update_addresses {
569 my $new_patron = shift;
573 my $current_id; # id of the address before creation
575 for my $address (@{$patron->addresses()}) {
577 next unless ref $address;
578 $current_id = $address->id();
580 if( $patron->billing_address() and
581 $patron->billing_address() == $current_id ) {
582 $logger->info("setting billing addr to $current_id");
583 $new_patron->billing_address($address->id());
584 $new_patron->ischanged(1);
587 if( $patron->mailing_address() and
588 $patron->mailing_address() == $current_id ) {
589 $new_patron->mailing_address($address->id());
590 $logger->info("setting mailing addr to $current_id");
591 $new_patron->ischanged(1);
595 if($address->isnew()) {
597 $address->usr($new_patron->id());
599 ($address, $evt) = _add_address($session,$address);
600 return (undef, $evt) if $evt;
602 # we need to get the new id
603 if( $patron->billing_address() and
604 $patron->billing_address() == $current_id ) {
605 $new_patron->billing_address($address->id());
606 $logger->info("setting billing addr to $current_id");
607 $new_patron->ischanged(1);
610 if( $patron->mailing_address() and
611 $patron->mailing_address() == $current_id ) {
612 $new_patron->mailing_address($address->id());
613 $logger->info("setting mailing addr to $current_id");
614 $new_patron->ischanged(1);
617 } elsif($address->ischanged() ) {
619 ($address, $evt) = _update_address($session, $address);
620 return (undef, $evt) if $evt;
622 } elsif($address->isdeleted() ) {
624 if( $address->id() == $new_patron->mailing_address() ) {
625 $new_patron->clear_mailing_address();
626 ($new_patron, $evt) = _update_patron($session, $new_patron);
627 return (undef, $evt) if $evt;
630 if( $address->id() == $new_patron->billing_address() ) {
631 $new_patron->clear_billing_address();
632 ($new_patron, $evt) = _update_patron($session, $new_patron);
633 return (undef, $evt) if $evt;
636 $evt = _delete_address($session, $address);
637 return (undef, $evt) if $evt;
641 return ( $new_patron, undef );
645 # adds an address to the db and returns the address with new id
647 my($session, $address) = @_;
648 $address->clear_id();
650 $logger->info("Creating new address at street ".$address->street1);
652 # put the address into the database
653 my $id = $session->request(
654 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
655 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
658 return ($address, undef);
662 sub _update_address {
663 my( $session, $address ) = @_;
665 $logger->info("Updating address ".$address->id." in the DB");
667 my $stat = $session->request(
668 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
670 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
671 return ($address, undef);
676 sub _add_update_cards {
680 my $new_patron = shift;
684 my $virtual_id; #id of the card before creation
685 for my $card (@{$patron->cards()}) {
687 $card->usr($new_patron->id());
689 if(ref($card) and $card->isnew()) {
691 $virtual_id = $card->id();
692 ( $card, $evt ) = _add_card($session,$card);
693 return (undef, $evt) if $evt;
695 #if(ref($patron->card)) { $patron->card($patron->card->id); }
696 if($patron->card() == $virtual_id) {
697 $new_patron->card($card->id());
698 $new_patron->ischanged(1);
701 } elsif( ref($card) and $card->ischanged() ) {
702 $evt = _update_card($session, $card);
703 return (undef, $evt) if $evt;
707 return ( $new_patron, undef );
711 # adds an card to the db and returns the card with new id
713 my( $session, $card ) = @_;
716 $logger->info("Adding new patron card ".$card->barcode);
718 my $id = $session->request(
719 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
720 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
721 $logger->info("Successfully created patron card $id");
724 return ( $card, undef );
728 # returns event on error. returns undef otherwise
730 my( $session, $card ) = @_;
731 $logger->info("Updating patron card ".$card->id);
733 my $stat = $session->request(
734 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
735 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
742 # returns event on error. returns undef otherwise
743 sub _delete_address {
744 my( $session, $address ) = @_;
746 $logger->info("Deleting address ".$address->id." from DB");
748 my $stat = $session->request(
749 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
751 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
757 sub _add_survey_responses {
758 my ($session, $patron, $new_patron) = @_;
760 $logger->info( "Updating survey responses for patron ".$new_patron->id );
762 my $responses = $patron->survey_responses;
766 $_->usr($new_patron->id) for (@$responses);
768 my $evt = $U->simplereq( "open-ils.circ",
769 "open-ils.circ.survey.submit.user_id", $responses );
771 return (undef, $evt) if defined($U->event_code($evt));
775 return ( $new_patron, undef );
779 sub _create_stat_maps {
781 my($session, $user_session, $patron, $new_patron) = @_;
783 my $maps = $patron->stat_cat_entries();
785 for my $map (@$maps) {
787 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
789 if ($map->isdeleted()) {
790 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
792 } elsif ($map->isnew()) {
793 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
798 $map->target_usr($new_patron->id);
801 $logger->info("Updating stat entry with method $method and map $map");
803 my $stat = $session->request($method, $map)->gather(1);
804 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
808 return ($new_patron, undef);
811 sub _create_perm_maps {
813 my($session, $user_session, $patron, $new_patron) = @_;
815 my $maps = $patron->permissions;
817 for my $map (@$maps) {
819 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
820 if ($map->isdeleted()) {
821 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
822 } elsif ($map->isnew()) {
823 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
828 $map->usr($new_patron->id);
830 #warn( "Updating permissions with method $method and session $user_session and map $map" );
831 $logger->info( "Updating permissions with method $method and map $map" );
833 my $stat = $session->request($method, $map)->gather(1);
834 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
838 return ($new_patron, undef);
842 __PACKAGE__->register_method(
843 method => "set_user_work_ous",
844 api_name => "open-ils.actor.user.work_ous.update",
847 sub set_user_work_ous {
853 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
856 my $session = $apputils->start_db_session();
858 for my $map (@$maps) {
860 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
861 if ($map->isdeleted()) {
862 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
863 } elsif ($map->isnew()) {
864 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
868 #warn( "Updating permissions with method $method and session $ses and map $map" );
869 $logger->info( "Updating work_ou map with method $method and map $map" );
871 my $stat = $session->request($method, $map)->gather(1);
872 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
876 $apputils->commit_db_session($session);
878 return scalar(@$maps);
882 __PACKAGE__->register_method(
883 method => "set_user_perms",
884 api_name => "open-ils.actor.user.permissions.update",
893 my $session = $apputils->start_db_session();
895 my( $user_obj, $evt ) = $U->checkses($ses);
898 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
901 $all = 1 if ($U->is_true($user_obj->super_user()));
902 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
904 for my $map (@$maps) {
906 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
907 if ($map->isdeleted()) {
908 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
909 } elsif ($map->isnew()) {
910 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
914 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
915 #warn( "Updating permissions with method $method and session $ses and map $map" );
916 $logger->info( "Updating permissions with method $method and map $map" );
918 my $stat = $session->request($method, $map)->gather(1);
919 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
923 $apputils->commit_db_session($session);
925 return scalar(@$maps);
929 __PACKAGE__->register_method(
930 method => "user_retrieve_by_barcode",
932 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
934 sub user_retrieve_by_barcode {
935 my($self, $client, $user_session, $barcode) = @_;
937 $logger->debug("Searching for user with barcode $barcode");
938 my ($user_obj, $evt) = $apputils->checkses($user_session);
941 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
943 "open-ils.cstore.direct.actor.card.search.atomic",
944 { barcode => $barcode }
947 if(!$card || !$card->[0]) {
948 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
952 my $user = flesh_user($card->usr(), new_editor(requestor => $user_obj));
954 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
957 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
964 __PACKAGE__->register_method(
965 method => "get_user_by_id",
967 api_name => "open-ils.actor.user.retrieve",);
970 my ($self, $client, $auth, $id) = @_;
971 my $e = new_editor(authtoken=>$auth);
972 return $e->event unless $e->checkauth;
973 my $user = $e->retrieve_actor_user($id)
975 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
981 __PACKAGE__->register_method(
982 method => "get_org_types",
983 api_name => "open-ils.actor.org_types.retrieve",);
986 return $U->get_org_types();
991 __PACKAGE__->register_method(
992 method => "get_user_ident_types",
993 api_name => "open-ils.actor.user.ident_types.retrieve",
996 sub get_user_ident_types {
997 return $ident_types if $ident_types;
998 return $ident_types =
999 new_editor()->retrieve_all_config_identification_type();
1005 __PACKAGE__->register_method(
1006 method => "get_org_unit",
1007 api_name => "open-ils.actor.org_unit.retrieve",
1011 my( $self, $client, $user_session, $org_id ) = @_;
1012 my $e = new_editor(authtoken => $user_session);
1014 return $e->event unless $e->checkauth;
1015 $org_id = $e->requestor->ws_ou;
1017 my $o = $e->retrieve_actor_org_unit($org_id)
1018 or return $e->event;
1022 __PACKAGE__->register_method(
1023 method => "search_org_unit",
1024 api_name => "open-ils.actor.org_unit_list.search",
1027 sub search_org_unit {
1029 my( $self, $client, $field, $value ) = @_;
1031 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1033 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1034 { $field => $value } );
1040 # build the org tree
1042 __PACKAGE__->register_method(
1043 method => "get_org_tree",
1044 api_name => "open-ils.actor.org_tree.retrieve",
1046 note => "Returns the entire org tree structure",
1052 return $U->get_org_tree($client->session->session_locale);
1056 __PACKAGE__->register_method(
1057 method => "get_org_descendants",
1058 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1061 # depth is optional. org_unit is the id
1062 sub get_org_descendants {
1063 my( $self, $client, $org_unit, $depth ) = @_;
1065 if(ref $org_unit eq 'ARRAY') {
1068 for my $i (0..scalar(@$org_unit)-1) {
1069 my $list = $U->simple_scalar_request(
1071 "open-ils.storage.actor.org_unit.descendants.atomic",
1072 $org_unit->[$i], $depth->[$i] );
1073 push(@trees, $U->build_org_tree($list));
1078 my $orglist = $apputils->simple_scalar_request(
1080 "open-ils.storage.actor.org_unit.descendants.atomic",
1081 $org_unit, $depth );
1082 return $U->build_org_tree($orglist);
1087 __PACKAGE__->register_method(
1088 method => "get_org_ancestors",
1089 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1092 # depth is optional. org_unit is the id
1093 sub get_org_ancestors {
1094 my( $self, $client, $org_unit, $depth ) = @_;
1095 my $orglist = $apputils->simple_scalar_request(
1097 "open-ils.storage.actor.org_unit.ancestors.atomic",
1098 $org_unit, $depth );
1099 return $U->build_org_tree($orglist);
1103 __PACKAGE__->register_method(
1104 method => "get_standings",
1105 api_name => "open-ils.actor.standings.retrieve"
1110 return $user_standings if $user_standings;
1111 return $user_standings =
1112 $apputils->simple_scalar_request(
1114 "open-ils.cstore.direct.config.standing.search.atomic",
1115 { id => { "!=" => undef } }
1121 __PACKAGE__->register_method(
1122 method => "get_my_org_path",
1123 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1126 sub get_my_org_path {
1127 my( $self, $client, $auth, $org_id ) = @_;
1128 my $e = new_editor(authtoken=>$auth);
1129 return $e->event unless $e->checkauth;
1130 $org_id = $e->requestor->ws_ou unless defined $org_id;
1132 return $apputils->simple_scalar_request(
1134 "open-ils.storage.actor.org_unit.full_path.atomic",
1139 __PACKAGE__->register_method(
1140 method => "patron_adv_search",
1141 api_name => "open-ils.actor.patron.search.advanced" );
1142 sub patron_adv_search {
1143 my( $self, $client, $auth, $search_hash,
1144 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1146 my $e = new_editor(authtoken=>$auth);
1147 return $e->event unless $e->checkauth;
1148 return $e->event unless $e->allowed('VIEW_USER');
1149 return $U->storagereq(
1150 "open-ils.storage.actor.user.crazy_search", $search_hash,
1151 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1155 __PACKAGE__->register_method(
1156 method => "update_passwd",
1158 api_name => "open-ils.actor.user.password.update");
1160 __PACKAGE__->register_method(
1161 method => "update_passwd",
1162 api_name => "open-ils.actor.user.username.update");
1164 __PACKAGE__->register_method(
1165 method => "update_passwd",
1166 api_name => "open-ils.actor.user.email.update");
1169 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1170 my $e = new_editor(xact=>1, authtoken=>$auth);
1171 return $e->die_event unless $e->checkauth;
1173 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1174 or return $e->die_event;
1175 my $api = $self->api_name;
1177 if( $api =~ /password/o ) {
1179 # make sure the original password matches the in-database password
1180 return OpenILS::Event->new('INCORRECT_PASSWORD')
1181 if md5_hex($orig_pw) ne $db_user->passwd;
1182 $db_user->passwd($new_val);
1186 # if we don't clear the password, the user will be updated with
1187 # a hashed version of the hashed version of their password
1188 $db_user->clear_passwd;
1190 if( $api =~ /username/o ) {
1192 # make sure no one else has this username
1193 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1194 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1195 $db_user->usrname($new_val);
1197 } elsif( $api =~ /email/o ) {
1198 $db_user->email($new_val);
1202 $e->update_actor_user($db_user) or return $e->die_event;
1210 __PACKAGE__->register_method(
1211 method => "check_user_perms",
1212 api_name => "open-ils.actor.user.perm.check",
1213 notes => <<" NOTES");
1214 Takes a login session, user id, an org id, and an array of perm type strings. For each
1215 perm type, if the user does *not* have the given permission it is added
1216 to a list which is returned from the method. If all permissions
1217 are allowed, an empty list is returned
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_perms {
1223 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1225 my( $staff, $evt ) = $apputils->checkses($login_session);
1226 return $evt if $evt;
1228 if($staff->id ne $user_id) {
1229 if( $evt = $apputils->check_perms(
1230 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1236 for my $perm (@$perm_types) {
1237 if($apputils->check_perms($user_id, $org_id, $perm)) {
1238 push @not_allowed, $perm;
1242 return \@not_allowed
1245 __PACKAGE__->register_method(
1246 method => "check_user_perms2",
1247 api_name => "open-ils.actor.user.perm.check.multi_org",
1249 Checks the permissions on a list of perms and orgs for a user
1250 @param authtoken The login session key
1251 @param user_id The id of the user to check
1252 @param orgs The array of org ids
1253 @param perms The array of permission names
1254 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1255 if the logged in user does not match 'user_id', then the logged in user must
1256 have VIEW_PERMISSION priveleges.
1259 sub check_user_perms2 {
1260 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1262 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1263 $authtoken, $user_id, 'VIEW_PERMISSION' );
1264 return $evt if $evt;
1267 for my $org (@$orgs) {
1268 for my $perm (@$perms) {
1269 if($apputils->check_perms($user_id, $org, $perm)) {
1270 push @not_allowed, [ $org, $perm ];
1275 return \@not_allowed
1279 __PACKAGE__->register_method(
1280 method => 'check_user_perms3',
1281 api_name => 'open-ils.actor.user.perm.highest_org',
1283 Returns the highest org unit id at which a user has a given permission
1284 If the requestor does not match the target user, the requestor must have
1285 'VIEW_PERMISSION' rights at the home org unit of the target user
1286 @param authtoken The login session key
1287 @param userid The id of the user in question
1288 @param perm The permission to check
1289 @return The org unit highest in the org tree within which the user has
1290 the requested permission
1293 sub check_user_perms3 {
1294 my($self, $client, $authtoken, $user_id, $perm) = @_;
1295 my $e = new_editor(authtoken=>$authtoken);
1296 return $e->event unless $e->checkauth;
1298 my $tree = $U->get_org_tree();
1300 unless($e->requestor->id == $user_id) {
1301 my $user = $e->retrieve_actor_user($user_id)
1302 or return $e->event;
1303 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1304 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1307 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1310 __PACKAGE__->register_method(
1311 method => 'user_has_work_perm_at',
1312 api_name => 'open-ils.actor.user.has_work_perm_at',
1316 Returns a set of org unit IDs which represent the highest orgs in
1317 the org tree where the user has the requested permission. The
1318 purpose of this method is to return the smallest set of org units
1319 which represent the full expanse of the user's ability to perform
1320 the requested action. The user whose perms this method should
1321 check is implied by the authtoken. /,
1323 {desc => 'authtoken', type => 'string'},
1324 {desc => 'permission name', type => 'string'},
1326 return => {desc => 'An array of org IDs'}
1330 sub user_has_work_perm_at {
1331 my($self, $conn, $auth, $perm) = @_;
1332 my $e = new_editor(authtoken=>$auth);
1333 return $e->event unless $e->checkauth;
1334 return $U->user_has_work_perm_at($e, $perm);
1337 __PACKAGE__->register_method(
1338 method => 'user_has_work_perm_at_batch',
1339 api_name => 'open-ils.actor.user.has_work_perm_at.batch',
1343 sub user_has_work_perm_at_batch {
1344 my($self, $conn, $auth, $perms) = @_;
1345 my $e = new_editor(authtoken=>$auth);
1346 return $e->event unless $e->checkauth;
1348 $map->{$_} = $U->user_has_work_perm_at($e, $_) for @$perms;
1354 __PACKAGE__->register_method(
1355 method => 'check_user_perms4',
1356 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1358 Returns the highest org unit id at which a user has a given permission
1359 If the requestor does not match the target user, the requestor must have
1360 'VIEW_PERMISSION' rights at the home org unit of the target user
1361 @param authtoken The login session key
1362 @param userid The id of the user in question
1363 @param perms An array of perm names to check
1364 @return An array of orgId's representing the org unit
1365 highest in the org tree within which the user has the requested permission
1366 The arrah of orgId's has matches the order of the perms array
1369 sub check_user_perms4 {
1370 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1372 my( $staff, $target, $org, $evt );
1374 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1375 $authtoken, $userid, 'VIEW_PERMISSION' );
1376 return $evt if $evt;
1379 return [] unless ref($perms);
1380 my $tree = $U->get_org_tree();
1382 for my $p (@$perms) {
1383 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1391 __PACKAGE__->register_method(
1392 method => "user_fines_summary",
1393 api_name => "open-ils.actor.user.fines.summary",
1395 notes => <<" NOTES");
1396 Returns a short summary of the users total open fines, excluding voided fines
1397 Params are login_session, user_id
1398 Returns a 'mous' object.
1401 sub user_fines_summary {
1402 my( $self, $client, $auth, $user_id ) = @_;
1403 my $e = new_editor(authtoken=>$auth);
1404 return $e->event unless $e->checkauth;
1405 my $user = $e->retrieve_actor_user($user_id)
1406 or return $e->event;
1408 if( $user_id ne $e->requestor->id ) {
1409 return $e->event unless
1410 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1413 # run this inside a transaction to prevent replication delay errors
1414 my $ses = $U->start_db_session();
1415 my $s = $ses->request(
1416 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1417 $U->rollback_db_session($ses);
1424 __PACKAGE__->register_method(
1425 method => "user_transactions",
1426 api_name => "open-ils.actor.user.transactions",
1427 notes => <<" NOTES");
1428 Returns a list of open user transactions (mbts objects);
1429 Params are login_session, user_id
1430 Optional third parameter is the transactions type. defaults to all
1433 __PACKAGE__->register_method(
1434 method => "user_transactions",
1435 api_name => "open-ils.actor.user.transactions.have_charge",
1436 notes => <<" NOTES");
1437 Returns a list of all open user transactions (mbts objects) that have an initial charge
1438 Params are login_session, user_id
1439 Optional third parameter is the transactions type. defaults to all
1442 __PACKAGE__->register_method(
1443 method => "user_transactions",
1444 api_name => "open-ils.actor.user.transactions.have_balance",
1445 notes => <<" NOTES");
1446 Returns a list of all open user transactions (mbts objects) that have a balance
1447 Params are login_session, user_id
1448 Optional third parameter is the transactions type. defaults to all
1451 __PACKAGE__->register_method(
1452 method => "user_transactions",
1453 api_name => "open-ils.actor.user.transactions.fleshed",
1454 notes => <<" NOTES");
1455 Returns an object/hash of transaction, circ, title where transaction = an open
1456 user transactions (mbts objects), circ is the attached circluation, and title
1457 is the title the circ points to
1458 Params are login_session, user_id
1459 Optional third parameter is the transactions type. defaults to all
1462 __PACKAGE__->register_method(
1463 method => "user_transactions",
1464 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1465 notes => <<" NOTES");
1466 Returns an object/hash of transaction, circ, title where transaction = an open
1467 user transactions that has an initial charge (mbts objects), circ is the
1468 attached circluation, and title is the title the circ points to
1469 Params are login_session, user_id
1470 Optional third parameter is the transactions type. defaults to all
1473 __PACKAGE__->register_method(
1474 method => "user_transactions",
1475 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1476 notes => <<" NOTES");
1477 Returns an object/hash of transaction, circ, title where transaction = an open
1478 user transaction that has a balance (mbts objects), circ is the attached
1479 circluation, and title is the title the circ points to
1480 Params are login_session, user_id
1481 Optional third parameter is the transaction type. defaults to all
1484 __PACKAGE__->register_method(
1485 method => "user_transactions",
1486 api_name => "open-ils.actor.user.transactions.count",
1487 notes => <<" NOTES");
1488 Returns an object/hash of transaction, circ, title where transaction = an open
1489 user transactions (mbts objects), circ is the attached circluation, and title
1490 is the title the circ points to
1491 Params are login_session, user_id
1492 Optional third parameter is the transactions type. defaults to all
1495 __PACKAGE__->register_method(
1496 method => "user_transactions",
1497 api_name => "open-ils.actor.user.transactions.have_charge.count",
1498 notes => <<" NOTES");
1499 Returns an object/hash of transaction, circ, title where transaction = an open
1500 user transactions that has an initial charge (mbts objects), circ is the
1501 attached circluation, and title is the title the circ points to
1502 Params are login_session, user_id
1503 Optional third parameter is the transactions type. defaults to all
1506 __PACKAGE__->register_method(
1507 method => "user_transactions",
1508 api_name => "open-ils.actor.user.transactions.have_balance.count",
1509 notes => <<" NOTES");
1510 Returns an object/hash of transaction, circ, title where transaction = an open
1511 user transaction that has a balance (mbts objects), circ is the attached
1512 circluation, and title is the title the circ points to
1513 Params are login_session, user_id
1514 Optional third parameter is the transaction type. defaults to all
1517 __PACKAGE__->register_method(
1518 method => "user_transactions",
1519 api_name => "open-ils.actor.user.transactions.have_balance.total",
1520 notes => <<" NOTES");
1521 Returns an object/hash of transaction, circ, title where transaction = an open
1522 user transaction that has a balance (mbts objects), circ is the attached
1523 circluation, and title is the title the circ points to
1524 Params are login_session, user_id
1525 Optional third parameter is the transaction type. defaults to all
1530 sub user_transactions {
1531 my( $self, $client, $login_session, $user_id, $type ) = @_;
1533 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1534 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1535 return $evt if $evt;
1537 my $api = $self->api_name();
1541 if(defined($type)) { @xact = (xact_type => $type);
1543 } else { @xact = (); }
1546 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1547 ->run($login_session => $user_id => $type);
1549 if($api =~ /have_charge/o) {
1551 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1553 } elsif($api =~ /have_balance/o) {
1555 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1558 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1562 if($api =~ /total/o) {
1564 for my $t (@$trans) {
1565 $total += $t->balance_owed;
1568 $logger->debug("Total balance owed by user $user_id: $total");
1572 if($api =~ /count/o) { return scalar @$trans; }
1573 if($api !~ /fleshed/o) { return $trans; }
1576 for my $t (@$trans) {
1578 if( $t->xact_type ne 'circulation' ) {
1579 push @resp, {transaction => $t};
1583 my $circ = $apputils->simple_scalar_request(
1585 "open-ils.cstore.direct.action.circulation.retrieve",
1590 my $title = $apputils->simple_scalar_request(
1592 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1593 $circ->target_copy );
1597 my $u = OpenILS::Utils::ModsParser->new();
1598 $u->start_mods_batch($title->marc());
1599 my $mods = $u->finish_mods_batch();
1600 $mods->doc_id($title->id) if $mods;
1602 push @resp, {transaction => $t, circ => $circ, record => $mods };
1610 __PACKAGE__->register_method(
1611 method => "user_transaction_retrieve",
1612 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1614 notes => <<" NOTES");
1615 Returns a fleshedtransaction record
1617 __PACKAGE__->register_method(
1618 method => "user_transaction_retrieve",
1619 api_name => "open-ils.actor.user.transaction.retrieve",
1621 notes => <<" NOTES");
1622 Returns a transaction record
1624 sub user_transaction_retrieve {
1625 my( $self, $client, $login_session, $bill_id ) = @_;
1627 # XXX I think I'm deprecated... make sure
1629 my $trans = $apputils->simple_scalar_request(
1631 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1635 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1636 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1637 return $evt if $evt;
1639 my $api = $self->api_name();
1640 if($api !~ /fleshed/o) { return $trans; }
1642 if( $trans->xact_type ne 'circulation' ) {
1643 $logger->debug("Returning non-circ transaction");
1644 return {transaction => $trans};
1647 my $circ = $apputils->simple_scalar_request(
1649 "open-ils..direct.action.circulation.retrieve",
1652 return {transaction => $trans} unless $circ;
1653 $logger->debug("Found the circ transaction");
1655 my $title = $apputils->simple_scalar_request(
1657 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1658 $circ->target_copy );
1660 return {transaction => $trans, circ => $circ } unless $title;
1661 $logger->debug("Found the circ title");
1665 my $u = OpenILS::Utils::ModsParser->new();
1666 $u->start_mods_batch($title->marc());
1667 $mods = $u->finish_mods_batch();
1669 if ($title->id == OILS_PRECAT_RECORD) {
1670 my $copy = $apputils->simple_scalar_request(
1672 "open-ils.cstore.direct.asset.copy.retrieve",
1673 $circ->target_copy );
1675 $mods = new Fieldmapper::metabib::virtual_record;
1676 $mods->doc_id(OILS_PRECAT_RECORD);
1677 $mods->title($copy->dummy_title);
1678 $mods->author($copy->dummy_author);
1682 $logger->debug("MODSized the circ title");
1684 return {transaction => $trans, circ => $circ, record => $mods };
1688 __PACKAGE__->register_method(
1689 method => "hold_request_count",
1690 api_name => "open-ils.actor.user.hold_requests.count",
1693 notes => <<" NOTES");
1694 Returns hold ready/total counts
1696 sub hold_request_count {
1697 my( $self, $client, $login_session, $userid ) = @_;
1699 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1700 $login_session, $userid, 'VIEW_HOLD' );
1701 return $evt if $evt;
1704 my $holds = $apputils->simple_scalar_request(
1706 "open-ils.cstore.direct.action.hold_request.search.atomic",
1709 fulfillment_time => {"=" => undef },
1710 cancel_time => undef,
1715 for my $h (@$holds) {
1716 next unless $h->capture_time and $h->current_copy;
1718 my $copy = $apputils->simple_scalar_request(
1720 "open-ils.cstore.direct.asset.copy.retrieve",
1724 if ($copy and $copy->status == 8) {
1729 return { total => scalar(@$holds), ready => scalar(@ready) };
1733 __PACKAGE__->register_method(
1734 method => "checkedout_count",
1735 api_name => "open-ils.actor.user.checked_out.count__",
1737 notes => <<" NOTES");
1738 Returns a transaction record
1742 sub checkedout_count {
1743 my( $self, $client, $login_session, $userid ) = @_;
1745 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1746 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1747 return $evt if $evt;
1749 my $circs = $apputils->simple_scalar_request(
1751 "open-ils.cstore.direct.action.circulation.search.atomic",
1752 { usr => $userid, stop_fines => undef }
1753 #{ usr => $userid, checkin_time => {"=" => undef } }
1756 my $parser = DateTime::Format::ISO8601->new;
1759 for my $c (@$circs) {
1760 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1761 my $due = $due_dt->epoch;
1763 if ($due < DateTime->today->epoch) {
1768 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1772 __PACKAGE__->register_method(
1773 method => "checked_out",
1774 api_name => "open-ils.actor.user.checked_out",
1778 Returns a structure of circulations objects sorted by
1779 out, overdue, lost, claims_returned, long_overdue.
1780 A list of IDs are returned of each type.
1781 lost, long_overdue, and claims_returned circ will not
1782 be "finished" (there is an outstanding balance or some
1783 other pending action on the circ).
1785 The .count method also includes a 'total' field which
1786 sums all "open" circs
1790 __PACKAGE__->register_method(
1791 method => "checked_out",
1792 api_name => "open-ils.actor.user.checked_out.count",
1795 signature => q/@see open-ils.actor.user.checked_out/
1799 my( $self, $conn, $auth, $userid ) = @_;
1801 my $e = new_editor(authtoken=>$auth);
1802 return $e->event unless $e->checkauth;
1804 if( $userid ne $e->requestor->id ) {
1805 my $user = $e->retrieve_actor_user($userid) or return $e->event;
1806 unless($e->allowed('VIEW_CIRCULATIONS', $user->home_ou)) {
1808 # see if there is a friend link allowing circ.view perms
1809 my $allowed = OpenILS::Application::Actor::Friends->friend_perm_allowed(
1810 $e, $userid, $e->requestor->id, 'circ.view');
1811 return $e->event unless $allowed;
1815 my $count = $self->api_name =~ /count/;
1816 return _checked_out( $count, $e, $userid );
1820 my( $iscount, $e, $userid ) = @_;
1821 my $meth = 'open-ils.storage.actor.user.checked_out';
1822 $meth = "$meth.count" if $iscount;
1823 return $U->storagereq($meth, $userid);
1827 sub _checked_out_WHAT {
1828 my( $iscount, $e, $userid ) = @_;
1830 my $circs = $e->search_action_circulation(
1831 { usr => $userid, stop_fines => undef });
1833 my $mcircs = $e->search_action_circulation(
1836 checkin_time => undef,
1837 xact_finish => undef,
1841 push( @$circs, @$mcircs );
1843 my $parser = DateTime::Format::ISO8601->new;
1845 # split the circs up into overdue and not-overdue circs
1847 for my $c (@$circs) {
1848 if( $c->due_date ) {
1849 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1850 my $due = $due_dt->epoch;
1851 if ($due < DateTime->today->epoch) {
1852 push @overdue, $c->id;
1861 # grab all of the lost, claims-returned, and longoverdue circs
1862 #my $open = $e->search_action_circulation(
1863 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1866 # these items have stop_fines, but no xact_finish, so money
1867 # is owed on them and they have not been checked in
1868 my $open = $e->search_action_circulation(
1871 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1872 xact_finish => undef,
1873 checkin_time => undef,
1878 my( @lost, @cr, @lo );
1879 for my $c (@$open) {
1880 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1881 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1882 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1888 total => @$circs + @lost + @cr + @lo,
1889 out => scalar(@out),
1890 overdue => scalar(@overdue),
1891 lost => scalar(@lost),
1892 claims_returned => scalar(@cr),
1893 long_overdue => scalar(@lo)
1899 overdue => \@overdue,
1901 claims_returned => \@cr,
1902 long_overdue => \@lo
1908 __PACKAGE__->register_method(
1909 method => "checked_in_with_fines",
1910 api_name => "open-ils.actor.user.checked_in_with_fines",
1913 signature => q/@see open-ils.actor.user.checked_out/
1915 sub checked_in_with_fines {
1916 my( $self, $conn, $auth, $userid ) = @_;
1918 my $e = new_editor(authtoken=>$auth);
1919 return $e->event unless $e->checkauth;
1921 if( $userid ne $e->requestor->id ) {
1922 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1925 # money is owed on these items and they are checked in
1926 my $open = $e->search_action_circulation(
1929 xact_finish => undef,
1930 checkin_time => { "!=" => undef },
1935 my( @lost, @cr, @lo );
1936 for my $c (@$open) {
1937 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1938 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1939 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1944 claims_returned => \@cr,
1945 long_overdue => \@lo
1957 __PACKAGE__->register_method(
1958 method => "user_transaction_history",
1959 api_name => "open-ils.actor.user.transactions.history",
1961 notes => <<" NOTES");
1962 Returns a list of billable transaction ids for a user, optionally by type
1964 __PACKAGE__->register_method(
1965 method => "user_transaction_history",
1966 api_name => "open-ils.actor.user.transactions.history.have_charge",
1968 notes => <<" NOTES");
1969 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1971 __PACKAGE__->register_method(
1972 method => "user_transaction_history",
1973 api_name => "open-ils.actor.user.transactions.history.have_balance",
1976 notes => <<" NOTES");
1977 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1979 __PACKAGE__->register_method(
1980 method => "user_transaction_history",
1981 api_name => "open-ils.actor.user.transactions.history.still_open",
1983 notes => <<" NOTES");
1984 Returns a list of billable transaction ids for a user that are not finished
1986 __PACKAGE__->register_method(
1987 method => "user_transaction_history",
1988 api_name => "open-ils.actor.user.transactions.history.have_bill",
1991 notes => <<" NOTES");
1992 Returns a list of billable transaction ids for a user that has billings
1995 sub user_transaction_history {
1996 my( $self, $conn, $auth, $userid, $type ) = @_;
1998 # run inside of a transaction to prevent replication delays
1999 my $e = new_editor(xact=>1, authtoken=>$auth);
2000 return $e->die_event unless $e->checkauth;
2002 if( $e->requestor->id ne $userid ) {
2003 return $e->die_event
2004 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2007 my $api = $self->api_name;
2008 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2010 my @xacts = @{ $e->search_money_billable_transaction(
2011 [ { usr => $userid, @xact_finish },
2013 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2014 order_by => { mbt => 'xact_start DESC' },
2022 my @mbts = $U->make_mbts( $e, @xacts );
2024 if(defined($type)) {
2025 @mbts = grep { $_->xact_type eq $type } @mbts;
2028 if($api =~ /have_balance/o) {
2029 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2032 if($api =~ /have_charge/o) {
2033 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2036 if($api =~ /have_bill/o) {
2037 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2045 __PACKAGE__->register_method(
2046 method => "user_perms",
2047 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2049 notes => <<" NOTES");
2050 Returns a list of permissions
2053 my( $self, $client, $authtoken, $user ) = @_;
2055 my( $staff, $evt ) = $apputils->checkses($authtoken);
2056 return $evt if $evt;
2058 $user ||= $staff->id;
2060 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2064 return $apputils->simple_scalar_request(
2066 "open-ils.storage.permission.user_perms.atomic",
2070 __PACKAGE__->register_method(
2071 method => "retrieve_perms",
2072 api_name => "open-ils.actor.permissions.retrieve",
2073 notes => <<" NOTES");
2074 Returns a list of permissions
2076 sub retrieve_perms {
2077 my( $self, $client ) = @_;
2078 return $apputils->simple_scalar_request(
2080 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2081 { id => { '!=' => undef } }
2085 __PACKAGE__->register_method(
2086 method => "retrieve_groups",
2087 api_name => "open-ils.actor.groups.retrieve",
2088 notes => <<" NOTES");
2089 Returns a list of user groupss
2091 sub retrieve_groups {
2092 my( $self, $client ) = @_;
2093 return new_editor()->retrieve_all_permission_grp_tree();
2096 __PACKAGE__->register_method(
2097 method => "retrieve_org_address",
2098 api_name => "open-ils.actor.org_unit.address.retrieve",
2099 notes => <<' NOTES');
2100 Returns an org_unit address by ID
2101 @param An org_address ID
2103 sub retrieve_org_address {
2104 my( $self, $client, $id ) = @_;
2105 return $apputils->simple_scalar_request(
2107 "open-ils.cstore.direct.actor.org_address.retrieve",
2112 __PACKAGE__->register_method(
2113 method => "retrieve_groups_tree",
2114 api_name => "open-ils.actor.groups.tree.retrieve",
2115 notes => <<" NOTES");
2116 Returns a list of user groups
2118 sub retrieve_groups_tree {
2119 my( $self, $client ) = @_;
2120 return new_editor()->search_permission_grp_tree(
2125 flesh_fields => { pgt => ["children"] },
2126 order_by => { pgt => 'name'}
2133 __PACKAGE__->register_method(
2134 method => "add_user_to_groups",
2135 api_name => "open-ils.actor.user.set_groups",
2136 notes => <<" NOTES");
2137 Adds a user to one or more permission groups
2140 sub add_user_to_groups {
2141 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2143 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2144 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2145 return $evt if $evt;
2147 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2148 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2149 return $evt if $evt;
2151 $apputils->simplereq(
2153 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2155 for my $group (@$groups) {
2156 my $link = Fieldmapper::permission::usr_grp_map->new;
2158 $link->usr($userid);
2160 my $id = $apputils->simplereq(
2162 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2168 __PACKAGE__->register_method(
2169 method => "get_user_perm_groups",
2170 api_name => "open-ils.actor.user.get_groups",
2171 notes => <<" NOTES");
2172 Retrieve a user's permission groups.
2176 sub get_user_perm_groups {
2177 my( $self, $client, $authtoken, $userid ) = @_;
2179 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2180 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2181 return $evt if $evt;
2183 return $apputils->simplereq(
2185 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2189 __PACKAGE__->register_method(
2190 method => "get_user_work_ous",
2191 api_name => "open-ils.actor.user.get_work_ous",
2192 notes => <<" NOTES");
2193 Retrieve a user's work org units.
2195 __PACKAGE__->register_method(
2196 method => "get_user_work_ous",
2197 api_name => "open-ils.actor.user.get_work_ous.ids",
2198 notes => <<" NOTES");
2199 Retrieve a user's work org units.
2203 sub get_user_work_ous {
2204 my( $self, $client, $auth, $userid ) = @_;
2205 my $e = new_editor(authtoken=>$auth);
2206 return $e->event unless $e->checkauth;
2207 $userid ||= $e->requestor->id;
2209 if($e->requestor->id != $userid) {
2210 my $user = $e->retrieve_actor_user($userid)
2211 or return $e->event;
2212 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2215 return $e->search_permission_usr_work_ou_map({usr => $userid})
2216 unless $self->api_name =~ /.ids$/;
2218 # client just wants a list of org IDs
2219 return $U->get_user_work_ou_ids($e, $userid);
2225 __PACKAGE__->register_method (
2226 method => 'register_workstation',
2227 api_name => 'open-ils.actor.workstation.register.override',
2228 signature => q/@see open-ils.actor.workstation.register/);
2230 __PACKAGE__->register_method (
2231 method => 'register_workstation',
2232 api_name => 'open-ils.actor.workstation.register',
2234 Registers a new workstion in the system
2235 @param authtoken The login session key
2236 @param name The name of the workstation id
2237 @param owner The org unit that owns this workstation
2238 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2239 if the name is already in use.
2242 sub register_workstation {
2243 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2245 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2246 return $e->die_event unless $e->checkauth;
2247 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2248 my $existing = $e->search_actor_workstation({name => $name})->[0];
2252 if( $self->api_name =~ /override/o ) {
2253 # workstation with the given name exists.
2255 if($owner ne $existing->owning_lib) {
2256 # if necessary, update the owning_lib of the workstation
2258 $logger->info("changing owning lib of workstation ".$existing->id.
2259 " from ".$existing->owning_lib." to $owner");
2260 return $e->die_event unless
2261 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2263 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2265 $existing->owning_lib($owner);
2266 return $e->die_event unless $e->update_actor_workstation($existing);
2272 "attempt to register an existing workstation. returning existing ID");
2275 return $existing->id;
2278 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2282 my $ws = Fieldmapper::actor::workstation->new;
2283 $ws->owning_lib($owner);
2285 $e->create_actor_workstation($ws) or return $e->die_event;
2287 return $ws->id; # note: editor sets the id on the new object for us
2290 __PACKAGE__->register_method (
2291 method => 'workstation_list',
2292 api_name => 'open-ils.actor.workstation.list',
2294 Returns a list of workstations registered at the given location
2295 @param authtoken The login session key
2296 @param ids A list of org_unit.id's for the workstation owners
2299 sub workstation_list {
2300 my( $self, $conn, $authtoken, @orgs ) = @_;
2302 my $e = new_editor(authtoken=>$authtoken);
2303 return $e->event unless $e->checkauth;
2308 unless $e->allowed('REGISTER_WORKSTATION', $o);
2309 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2320 __PACKAGE__->register_method (
2321 method => 'fetch_patron_note',
2322 api_name => 'open-ils.actor.note.retrieve.all',
2325 Returns a list of notes for a given user
2326 Requestor must have VIEW_USER permission if pub==false and
2327 @param authtoken The login session key
2328 @param args Hash of params including
2329 patronid : the patron's id
2330 pub : true if retrieving only public notes
2334 sub fetch_patron_note {
2335 my( $self, $conn, $authtoken, $args ) = @_;
2336 my $patronid = $$args{patronid};
2338 my($reqr, $evt) = $U->checkses($authtoken);
2339 return $evt if $evt;
2342 ($patron, $evt) = $U->fetch_user($patronid);
2343 return $evt if $evt;
2346 if( $patronid ne $reqr->id ) {
2347 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2348 return $evt if $evt;
2350 return $U->cstorereq(
2351 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2352 { usr => $patronid, pub => 't' } );
2355 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2356 return $evt if $evt;
2358 return $U->cstorereq(
2359 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2362 __PACKAGE__->register_method (
2363 method => 'create_user_note',
2364 api_name => 'open-ils.actor.note.create',
2366 Creates a new note for the given user
2367 @param authtoken The login session key
2368 @param note The note object
2371 sub create_user_note {
2372 my( $self, $conn, $authtoken, $note ) = @_;
2373 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2374 return $e->die_event unless $e->checkauth;
2376 my $user = $e->retrieve_actor_user($note->usr)
2377 or return $e->die_event;
2379 return $e->die_event unless
2380 $e->allowed('UPDATE_USER',$user->home_ou);
2382 $note->creator($e->requestor->id);
2383 $e->create_actor_usr_note($note) or return $e->die_event;
2389 __PACKAGE__->register_method (
2390 method => 'delete_user_note',
2391 api_name => 'open-ils.actor.note.delete',
2393 Deletes a note for the given user
2394 @param authtoken The login session key
2395 @param noteid The note id
2398 sub delete_user_note {
2399 my( $self, $conn, $authtoken, $noteid ) = @_;
2401 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2402 return $e->die_event unless $e->checkauth;
2403 my $note = $e->retrieve_actor_usr_note($noteid)
2404 or return $e->die_event;
2405 my $user = $e->retrieve_actor_user($note->usr)
2406 or return $e->die_event;
2407 return $e->die_event unless
2408 $e->allowed('UPDATE_USER', $user->home_ou);
2410 $e->delete_actor_usr_note($note) or return $e->die_event;
2416 __PACKAGE__->register_method (
2417 method => 'update_user_note',
2418 api_name => 'open-ils.actor.note.update',
2420 @param authtoken The login session key
2421 @param note The note
2425 sub update_user_note {
2426 my( $self, $conn, $auth, $note ) = @_;
2427 my $e = new_editor(authtoken=>$auth, xact=>1);
2428 return $e->event unless $e->checkauth;
2429 my $patron = $e->retrieve_actor_user($note->usr)
2430 or return $e->event;
2431 return $e->event unless
2432 $e->allowed('UPDATE_USER', $patron->home_ou);
2433 $e->update_actor_user_note($note)
2434 or return $e->event;
2442 __PACKAGE__->register_method (
2443 method => 'create_closed_date',
2444 api_name => 'open-ils.actor.org_unit.closed_date.create',
2446 Creates a new closing entry for the given org_unit
2447 @param authtoken The login session key
2448 @param note The closed_date object
2451 sub create_closed_date {
2452 my( $self, $conn, $authtoken, $cd ) = @_;
2454 my( $user, $evt ) = $U->checkses($authtoken);
2455 return $evt if $evt;
2457 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2458 return $evt if $evt;
2460 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2462 my $id = $U->storagereq(
2463 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2464 return $U->DB_UPDATE_FAILED($cd) unless $id;
2469 __PACKAGE__->register_method (
2470 method => 'delete_closed_date',
2471 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2473 Deletes a closing entry for the given org_unit
2474 @param authtoken The login session key
2475 @param noteid The close_date id
2478 sub delete_closed_date {
2479 my( $self, $conn, $authtoken, $cd ) = @_;
2481 my( $user, $evt ) = $U->checkses($authtoken);
2482 return $evt if $evt;
2485 ($cd_obj, $evt) = fetch_closed_date($cd);
2486 return $evt if $evt;
2488 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2489 return $evt if $evt;
2491 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2493 my $stat = $U->storagereq(
2494 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2495 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2500 __PACKAGE__->register_method(
2501 method => 'usrname_exists',
2502 api_name => 'open-ils.actor.username.exists',
2504 Returns 1 if the requested username exists, returns 0 otherwise
2508 sub usrname_exists {
2509 my( $self, $conn, $auth, $usrname ) = @_;
2510 my $e = new_editor(authtoken=>$auth);
2511 return $e->event unless $e->checkauth;
2512 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2513 return $$a[0] if $a and @$a;
2517 __PACKAGE__->register_method(
2518 method => 'barcode_exists',
2519 api_name => 'open-ils.actor.barcode.exists',
2522 Returns 1 if the requested barcode exists, returns 0 otherwise
2526 sub barcode_exists {
2527 my( $self, $conn, $auth, $barcode ) = @_;
2528 my $e = new_editor(authtoken=>$auth);
2529 return $e->event unless $e->checkauth;
2530 my $card = $e->search_actor_card({barcode => $barcode});
2536 #return undef unless @$card;
2537 #return $card->[0]->usr;
2541 __PACKAGE__->register_method(
2542 method => 'retrieve_net_levels',
2543 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2546 sub retrieve_net_levels {
2547 my( $self, $conn, $auth ) = @_;
2548 my $e = new_editor(authtoken=>$auth);
2549 return $e->event unless $e->checkauth;
2550 return $e->retrieve_all_config_net_access_level();
2554 __PACKAGE__->register_method(
2555 method => 'fetch_org_by_shortname',
2556 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2558 sub fetch_org_by_shortname {
2559 my( $self, $conn, $sname ) = @_;
2560 my $e = new_editor();
2561 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2562 return $e->event unless $org;
2567 __PACKAGE__->register_method(
2568 method => 'session_home_lib',
2569 api_name => 'open-ils.actor.session.home_lib',
2572 sub session_home_lib {
2573 my( $self, $conn, $auth ) = @_;
2574 my $e = new_editor(authtoken=>$auth);
2575 return undef unless $e->checkauth;
2576 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2577 return $org->shortname;
2580 __PACKAGE__->register_method(
2581 method => 'session_safe_token',
2582 api_name => 'open-ils.actor.session.safe_token',
2584 Returns a hashed session ID that is safe for export to the world.
2585 This safe token will expire after 1 hour of non-use.
2586 @param auth Active authentication token
2590 sub session_safe_token {
2591 my( $self, $conn, $auth ) = @_;
2592 my $e = new_editor(authtoken=>$auth);
2593 return undef unless $e->checkauth;
2595 my $safe_token = md5_hex($auth);
2597 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2599 # Add more like the following if needed...
2601 "safe-token-home_lib-shortname-$safe_token",
2602 $e->retrieve_actor_org_unit(
2603 $e->requestor->home_ou
2612 __PACKAGE__->register_method(
2613 method => 'safe_token_home_lib',
2614 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2616 Returns the home library shortname from the session
2617 asscociated with a safe token from generated by
2618 open-ils.actor.session.safe_token.
2619 @param safe_token Active safe token
2623 sub safe_token_home_lib {
2624 my( $self, $conn, $safe_token ) = @_;
2626 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2627 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2632 __PACKAGE__->register_method(
2633 method => 'slim_tree',
2634 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2637 my $tree = new_editor()->search_actor_org_unit(
2639 {"parent_ou" => undef },
2642 flesh_fields => { aou => ['children'] },
2643 order_by => { aou => 'name'},
2644 select => { aou => ["id","shortname", "name"]},
2649 return trim_tree($tree);
2655 return undef unless $tree;
2657 code => $tree->shortname,
2658 name => $tree->name,
2660 if( $tree->children and @{$tree->children} ) {
2661 $htree->{children} = [];
2662 for my $c (@{$tree->children}) {
2663 push( @{$htree->{children}}, trim_tree($c) );
2671 __PACKAGE__->register_method(
2672 method => "update_penalties",
2673 api_name => "open-ils.actor.user.penalties.update");
2675 sub update_penalties {
2676 my($self, $conn, $auth, $user_id) = @_;
2677 my $e = new_editor(authtoken=>$auth, xact => 1);
2678 return $e->die_event unless $e->checkauth;
2679 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2680 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2681 my $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $e->requestor->ws_ou);
2682 return $evt if $evt;
2688 __PACKAGE__->register_method(
2689 method => "apply_penalty",
2690 api_name => "open-ils.actor.user.penalty.apply");
2693 my($self, $conn, $auth, $penalty) = @_;
2694 my $e = new_editor(authtoken=>$auth, xact => 1);
2695 return $e->die_event unless $e->checkauth;
2696 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2697 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2699 # is it already applied?
2700 return 1 if $e->search_actor_user_standing_penalty(
2701 { usr => $penalty->usr,
2702 standing_penalty => $penalty->standing_penalty,
2703 org_unit => $penalty->org_unit
2706 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
2708 return $penalty->id;
2711 __PACKAGE__->register_method(
2712 method => "remove_penalty",
2713 api_name => "open-ils.actor.user.penalty.remove");
2715 sub remove_penalty {
2716 my($self, $conn, $auth, $penalty) = @_;
2717 my $e = new_editor(authtoken=>$auth, xact => 1);
2718 return $e->die_event unless $e->checkauth;
2719 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2720 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2722 $e->delete_actor_user_standing_penalty($penalty) or return $e->die_event;
2727 __PACKAGE__->register_method(
2728 method => "update_penalty_note",
2729 api_name => "open-ils.actor.user.penalty.note.update");
2731 sub update_penalty_note {
2732 my($self, $conn, $auth, $penalty_ids, $note) = @_;
2733 my $e = new_editor(authtoken=>$auth, xact => 1);
2734 return $e->die_event unless $e->checkauth;
2735 for my $penalty_id (@$penalty_ids) {
2736 my $penalty = $e->search_actor_user_standing_penalty( { id => $penalty_id } )->[0];
2737 if (! $penalty ) { return $e->die_event; }
2738 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2739 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2741 $penalty->note( $note ); $penalty->ischanged( 1 );
2743 $e->update_actor_user_standing_penalty($penalty) or return $e->die_event;
2749 __PACKAGE__->register_method(
2750 method => "ranged_penalty_thresholds",
2751 api_name => "open-ils.actor.grp_penalty_threshold.ranged.retrieve",
2755 sub ranged_penalty_thresholds {
2756 my($self, $conn, $auth, $context_org) = @_;
2757 my $e = new_editor(authtoken=>$auth);
2758 return $e->event unless $e->checkauth;
2759 return $e->event unless $e->allowed('VIEW_GROUP_PENALTY_THRESHOLD', $context_org);
2760 my $list = $e->search_permission_grp_penalty_threshold([
2761 {org_unit => $U->get_org_ancestors($context_org)},
2762 {order_by => {pgpt => 'id'}}
2764 $conn->respond($_) for @$list;
2770 __PACKAGE__->register_method(
2771 method => "user_retrieve_fleshed_by_id",
2773 api_name => "open-ils.actor.user.fleshed.retrieve",);
2775 sub user_retrieve_fleshed_by_id {
2776 my( $self, $client, $auth, $user_id, $fields ) = @_;
2777 my $e = new_editor(authtoken => $auth);
2778 return $e->event unless $e->checkauth;
2780 if( $e->requestor->id != $user_id ) {
2781 return $e->event unless $e->allowed('VIEW_USER');
2787 "standing_penalties",
2791 "stat_cat_entries" ];
2792 return new_flesh_user($user_id, $fields, $e);
2796 sub new_flesh_user {
2799 my $fields = shift || [];
2802 my $fetch_penalties = 0;
2803 if(grep {$_ eq 'standing_penalties'} @$fields) {
2804 $fields = [grep {$_ ne 'standing_penalties'} @$fields];
2805 $fetch_penalties = 1;
2808 my $user = $e->retrieve_actor_user(
2813 "flesh_fields" => { "au" => $fields }
2816 ) or return $e->event;
2819 if( grep { $_ eq 'addresses' } @$fields ) {
2821 $user->addresses([]) unless @{$user->addresses};
2822 # don't expose "replaced" addresses by default
2823 $user->addresses([grep {$_->id >= 0} @{$user->addresses}]);
2825 if( ref $user->billing_address ) {
2826 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2827 push( @{$user->addresses}, $user->billing_address );
2831 if( ref $user->mailing_address ) {
2832 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2833 push( @{$user->addresses}, $user->mailing_address );
2838 if($fetch_penalties) {
2839 # grab the user penalties ranged for this location
2840 $user->standing_penalties(
2841 $e->search_actor_user_standing_penalty([
2843 org_unit => $U->get_org_ancestors($e->requestor->ws_ou)
2846 flesh_fields => {ausp => ['standing_penalty']}
2853 $user->clear_passwd();
2860 __PACKAGE__->register_method(
2861 method => "user_retrieve_parts",
2862 api_name => "open-ils.actor.user.retrieve.parts",);
2864 sub user_retrieve_parts {
2865 my( $self, $client, $auth, $user_id, $fields ) = @_;
2866 my $e = new_editor(authtoken => $auth);
2867 return $e->event unless $e->checkauth;
2868 if( $e->requestor->id != $user_id ) {
2869 return $e->event unless $e->allowed('VIEW_USER');
2872 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2873 push(@resp, $user->$_()) for(@$fields);
2879 __PACKAGE__->register_method(
2880 method => 'user_opt_in_enabled',
2881 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2883 @return 1 if user opt-in is globally enabled, 0 otherwise.
2886 sub user_opt_in_enabled {
2887 my($self, $conn) = @_;
2888 my $sc = OpenSRF::Utils::SettingsClient->new;
2889 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2894 __PACKAGE__->register_method(
2895 method => 'user_opt_in_at_org',
2896 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2898 @param $auth The auth token
2899 @param user_id The ID of the user to test
2900 @return 1 if the user has opted in at the specified org,
2901 event on error, and 0 otherwise. /);
2902 sub user_opt_in_at_org {
2903 my($self, $conn, $auth, $user_id) = @_;
2905 # see if we even need to enforce the opt-in value
2906 return 1 unless user_opt_in_enabled($self);
2908 my $e = new_editor(authtoken => $auth);
2909 return $e->event unless $e->checkauth;
2910 my $org_id = $e->requestor->ws_ou;
2912 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2913 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2915 # user is automatically opted-in at the home org
2916 return 1 if $user->home_ou eq $org_id;
2918 my $vals = $e->search_actor_usr_org_unit_opt_in(
2919 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2925 __PACKAGE__->register_method(
2926 method => 'create_user_opt_in_at_org',
2927 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2929 @param $auth The auth token
2930 @param user_id The ID of the user to test
2931 @return The ID of the newly created object, event on error./);
2933 sub create_user_opt_in_at_org {
2934 my($self, $conn, $auth, $user_id) = @_;
2936 my $e = new_editor(authtoken => $auth, xact=>1);
2937 return $e->die_event unless $e->checkauth;
2938 my $org_id = $e->requestor->ws_ou;
2940 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2941 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2943 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2945 $opt_in->org_unit($org_id);
2946 $opt_in->usr($user_id);
2947 $opt_in->staff($e->requestor->id);
2948 $opt_in->opt_in_ts('now');
2949 $opt_in->opt_in_ws($e->requestor->wsid);
2951 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2952 or return $e->die_event;
2960 __PACKAGE__->register_method (
2961 method => 'retrieve_org_hours',
2962 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
2964 Returns the hours of operation for a specified org unit
2965 @param authtoken The login session key
2966 @param org_id The org_unit ID
2970 sub retrieve_org_hours {
2971 my($self, $conn, $auth, $org_id) = @_;
2972 my $e = new_editor(authtoken => $auth);
2973 return $e->die_event unless $e->checkauth;
2974 $org_id ||= $e->requestor->ws_ou;
2975 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);
2979 __PACKAGE__->register_method (
2980 method => 'verify_user_password',
2981 api_name => 'open-ils.actor.verify_user_password',
2983 Given a barcode or username and the MD5 encoded password,
2984 returns 1 if the password is correct. Returns 0 otherwise.
2988 sub verify_user_password {
2989 my($self, $conn, $auth, $barcode, $username, $password) = @_;
2990 my $e = new_editor(authtoken => $auth);
2991 return $e->die_event unless $e->checkauth;
2993 my $user_by_barcode;
2994 my $user_by_username;
2996 my $card = $e->search_actor_card([
2997 {barcode => $barcode},
2998 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return 0;
2999 $user_by_barcode = $card->usr;
3000 $user = $user_by_barcode;
3003 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return 0;
3004 $user = $user_by_username;
3006 return 0 if (!$user);
3007 return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3008 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3009 return 1 if $user->passwd eq $password;
3013 __PACKAGE__->register_method (
3014 method => 'retrieve_usr_id_via_barcode_or_usrname',
3015 api_name => "open-ils.actor.user.retrieve_id_by_barcode_or_username",
3017 Given a barcode or username returns the id for the user or
3022 sub retrieve_usr_id_via_barcode_or_usrname {
3023 my($self, $conn, $auth, $barcode, $username) = @_;
3024 my $e = new_editor(authtoken => $auth);
3025 return $e->die_event unless $e->checkauth;
3027 my $user_by_barcode;
3028 my $user_by_username;
3030 my $card = $e->search_actor_card([
3031 {barcode => $barcode},
3032 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
3033 $user_by_barcode = $card->usr;
3034 $user = $user_by_barcode;
3037 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
3039 $user = $user_by_username;
3041 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if (!$user);
3042 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3043 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3048 __PACKAGE__->register_method (
3049 method => 'merge_users',
3050 api_name => 'open-ils.actor.user.merge',
3053 Given a list of source users and destination user, transfer all data from the source
3054 to the dest user and delete the source user. All user related data is
3055 transferred, including circulations, holds, bookbags, etc.
3061 my($self, $conn, $auth, $master_id, $user_ids, $options) = @_;
3062 my $e = new_editor(xact => 1, authtoken => $auth);
3063 return $e->die_event unless $e->checkauth;
3065 my $master_user = $e->retrieve_actor_user($master_id) or return $e->die_event;
3066 my $del_addrs = ($U->ou_ancestor_setting_value(
3067 $master_user->home_ou, 'circ.user_merge.delete_addresses', $e)) ? 't' : 'f';
3068 my $del_cards = ($U->ou_ancestor_setting_value(
3069 $master_user->home_ou, 'circ.user_merge.delete_cards', $e)) ? 't' : 'f';
3070 my $deactivate_cards = ($U->ou_ancestor_setting_value(
3071 $master_user->home_ou, 'circ.user_merge.deactivate_cards', $e)) ? 't' : 'f';
3073 for my $src_id (@$user_ids) {
3074 my $src_user = $e->retrieve_actor_user($src_id) or return $e->die_event;
3076 return $e->die_event unless $e->allowed('MERGE_USERS', $src_user->home_ou);
3077 if($src_user->home_ou ne $master_user->home_ou) {
3078 return $e->die_event unless $e->allowed('MERGE_USERS', $master_user->home_ou);
3081 return $e->die_event unless
3082 $e->json_query({from => [
3097 __PACKAGE__->register_method (
3098 method => 'approve_user_address',
3099 api_name => 'open-ils.actor.user.pending_address.approve',
3106 sub approve_user_address {
3107 my($self, $conn, $auth, $addr) = @_;
3108 my $e = new_editor(xact => 1, authtoken => $auth);
3109 return $e->die_event unless $e->checkauth;
3111 # if the caller passes an address object, assume they want to
3112 # update it first before approving it
3113 $e->update_actor_user_address($addr) or return $e->die_event;
3115 $addr = $e->retrieve_actor_user_address($addr) or return $e->die_event;
3117 my $user = $e->retrieve_actor_user($addr->usr);
3118 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3119 my $result = $e->json_query({from => ['actor.approve_pending_address', $addr->id]})->[0]
3120 or return $e->die_event;
3122 return [values %$result]->[0];
3126 __PACKAGE__->register_method (
3127 method => 'retrieve_friends',
3128 api_name => 'open-ils.actor.friends.retrieve',
3131 returns { confirmed: [], pending_out: [], pending_in: []}
3132 pending_out are users I'm requesting friendship with
3133 pending_in are users requesting friendship with me
3138 sub retrieve_friends {
3139 my($self, $conn, $auth, $user_id, $options) = @_;
3140 my $e = new_editor(authtoken => $auth);
3141 return $e->event unless $e->checkauth;
3142 $user_id ||= $e->requestor->id;
3144 if($user_id != $e->requestor->id) {
3145 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3146 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3149 return OpenILS::Application::Actor::Friends->retrieve_friends(
3150 $e, $user_id, $options);
3155 __PACKAGE__->register_method (
3156 method => 'apply_friend_perms',
3157 api_name => 'open-ils.actor.friends.perms.apply',
3163 sub apply_friend_perms {
3164 my($self, $conn, $auth, $user_id, $delegate_id, @perms) = @_;
3165 my $e = new_editor(authtoken => $auth, xact => 1);
3166 return $e->event unless $e->checkauth;
3168 if($user_id != $e->requestor->id) {
3169 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3170 return $e->die_event unless $e->allowed('VIEW_USER', $user->home_ou);
3173 for my $perm (@perms) {
3175 OpenILS::Application::Actor::Friends->apply_friend_perm(
3176 $e, $user_id, $delegate_id, $perm);
3177 return $evt if $evt;
3185 __PACKAGE__->register_method (
3186 method => 'update_user_pending_address',
3187 api_name => 'open-ils.actor.user.address.pending.cud'
3190 sub update_user_pending_address {
3191 my($self, $conn, $auth, $addr) = @_;
3192 my $e = new_editor(authtoken => $auth, xact => 1);
3193 return $e->event unless $e->checkauth;
3195 if($addr->usr != $e->requestor->id) {
3196 my $user = $e->retrieve_actor_user($addr->usr) or return $e->die_event;
3197 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3201 $e->create_actor_user_address($addr) or return $e->die_event;
3202 } elsif($addr->isdeleted) {
3203 $e->delete_actor_user_address($addr) or return $e->die_event;
3205 $e->update_actor_user_address($addr) or return $e->die_event;
3213 __PACKAGE__->register_method (
3214 method => 'user_events',
3215 api_name => 'open-ils.actor.user.events.circ',
3218 __PACKAGE__->register_method (
3219 method => 'user_events',
3220 api_name => 'open-ils.actor.user.events.ahr',
3225 my($self, $conn, $auth, $user_id, $filters) = @_;
3226 my $e = new_editor(authtoken => $auth);
3227 return $e->event unless $e->checkauth;
3229 (my $obj_type = $self->api_name) =~ s/.*\.([a-z]+)$/$1/;
3230 my $user_field = 'usr';
3233 $filters->{target} = {
3234 select => { $obj_type => ['id'] },
3236 where => {usr => $user_id}
3239 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3240 if($e->requestor->id != $user_id) {
3241 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3244 my $ses = OpenSRF::AppSession->create('open-ils.trigger');
3245 my $req = $ses->request('open-ils.trigger.events_by_target',
3246 $obj_type, $filters, {atevdef => ['reactor', 'validator']}, 2);
3248 while(my $resp = $req->recv) {
3249 my $val = $resp->content;
3250 my $tgt = $val->target;
3252 if($obj_type eq 'circ') {
3253 $tgt->target_copy($e->retrieve_asset_copy($tgt->target_copy));
3255 } elsif($obj_type eq 'ahr') {
3256 $tgt->current_copy($e->retrieve_asset_copy($tgt->current_copy))
3257 if $tgt->current_copy;
3260 $conn->respond($val) if $val;
3267 __PACKAGE__->register_method (
3268 method => 'update_events',
3269 api_name => 'open-ils.actor.user.event.cancel.batch',
3272 __PACKAGE__->register_method (
3273 method => 'update_events',
3274 api_name => 'open-ils.actor.user.event.reset.batch',
3279 my($self, $conn, $auth, $event_ids) = @_;
3280 my $e = new_editor(xact => 1, authtoken => $auth);
3281 return $e->die_event unless $e->checkauth;
3284 for my $id (@$event_ids) {
3286 # do a little dance to determine what user we are ultimately affecting
3287 my $event = $e->retrieve_action_trigger_event([
3290 flesh_fields => {atev => ['event_def'], atevdef => ['hook']}
3292 ]) or return $e->die_event;
3295 if($event->event_def->hook->core_type eq 'circ') {
3296 $user_id = $e->retrieve_action_circulation($event->target)->usr;
3297 } elsif($event->event_def->hook->core_type eq 'ahr') {
3298 $user_id = $e->retrieve_action_hold_request($event->target)->usr;
3303 my $user = $e->retrieve_actor_user($user_id);
3304 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3306 if($self->api_name =~ /cancel/) {
3307 $event->state('invalid');
3308 } elsif($self->api_name =~ /reset/) {
3309 $event->clear_start_time;
3310 $event->clear_update_time;
3311 $event->state('pending');
3314 $e->update_action_trigger_event($event) or return $e->die_event;
3315 $conn->respond({maximum => scalar(@$event_ids), progress => $x++});
3319 return {complete => 1};