1 package OpenILS::Application::Actor;
2 use OpenILS::Application;
3 use base qw/OpenILS::Application/;
4 use strict; use warnings;
6 $Data::Dumper::Indent = 0;
9 use Digest::MD5 qw(md5_hex);
11 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::ModsParser;
18 use OpenSRF::Utils::Logger qw/$logger/;
19 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::SettingsClient;
22 use OpenSRF::Utils::Cache;
24 use OpenSRF::Utils::JSON;
26 use DateTime::Format::ISO8601;
27 use OpenILS::Const qw/:const/;
29 use OpenILS::Application::Actor::Container;
30 use OpenILS::Application::Actor::ClosedDates;
32 use OpenILS::Utils::CStoreEditor qw/:funcs/;
34 use OpenILS::Application::Actor::UserGroups;
36 OpenILS::Application::Actor::Container->initialize();
37 OpenILS::Application::Actor::UserGroups->initialize();
38 OpenILS::Application::Actor::ClosedDates->initialize();
41 my $apputils = "OpenILS::Application::AppUtils";
44 sub _d { warn "Patron:\n" . Dumper(shift()); }
49 my $set_user_settings;
52 __PACKAGE__->register_method(
53 method => "set_user_settings",
54 api_name => "open-ils.actor.patron.settings.update",
56 sub set_user_settings {
57 my( $self, $client, $user_session, $uid, $settings ) = @_;
59 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
61 my( $staff, $user, $evt ) =
62 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
66 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
68 $_->[1]->{value} = OpenSRF::Utils::JSON->perl2JSON($_->[1]->{value}) for @params;
70 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
72 my $ses = $U->start_db_session();
73 my $stat = $ses->request(
74 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
75 $U->commit_db_session($ses);
81 __PACKAGE__->register_method(
82 method => "set_ou_settings",
83 api_name => "open-ils.actor.org_unit.settings.update",
86 my( $self, $client, $auth, $org_id, $settings ) = @_;
88 my $e = new_editor(authtoken => $auth, xact => 1);
89 return $e->die_event unless $e->checkauth;
90 return $e->die_event unless $e->allowed('UPDATE_ORG_SETTING', $org_id);
92 for my $name (keys %$settings) {
93 my $val = $$settings{$name};
94 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
97 $val = OpenSRF::Utils::JSON->perl2JSON($val);
100 $e->update_actor_org_unit_setting($set) or return $e->die_event;
102 $set = Fieldmapper::actor::org_unit_setting->new;
103 $set->org_unit($org_id);
106 $e->create_actor_org_unit_setting($set) or return $e->die_event;
109 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
117 my $fetch_user_settings;
118 my $fetch_ou_settings;
120 __PACKAGE__->register_method(
121 method => "user_settings",
122 api_name => "open-ils.actor.patron.settings.retrieve",
125 my( $self, $client, $auth, $user_id, $setting ) = @_;
127 my $e = new_editor(authtoken => $auth);
128 return $e->event unless $e->checkauth;
130 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
131 if($e->requestor->id != $user_id) {
132 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
135 my $s = $e->search_actor_user_setting({usr => $user_id});
136 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
138 return $$settings{$setting} if $setting;
144 __PACKAGE__->register_method(
145 method => "ou_settings",
146 api_name => "open-ils.actor.org_unit.settings.retrieve",
149 my( $self, $client, $ouid ) = @_;
151 $logger->info("Fetching org unit settings for org $ouid");
153 my $s = $apputils->simplereq(
155 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
157 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
162 __PACKAGE__->register_method(
163 api_name => 'open-ils.actor.ou_setting.ancestor_default',
164 method => 'ou_ancestor_setting',
167 # ------------------------------------------------------------------
168 # Attempts to find the org setting value for a given org. if not
169 # found at the requested org, searches up the org tree until it
170 # finds a parent that has the requested setting.
171 # when found, returns { org => $id, value => $value }
172 # otherwise, returns NULL
173 # ------------------------------------------------------------------
174 sub ou_ancestor_setting {
175 my( $self, $client, $orgid, $name ) = @_;
176 return $U->ou_ancestor_setting($orgid, $name);
182 __PACKAGE__->register_method (
183 method => "ou_setting_delete",
184 api_name => 'open-ils.actor.org_setting.delete',
186 Deletes a specific org unit setting for a specific location
187 @param authtoken The login session key
188 @param orgid The org unit whose setting we're changing
189 @param setting The name of the setting to delete
190 @return True value on success.
194 sub ou_setting_delete {
195 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
196 my( $reqr, $evt) = $U->checkses($authtoken);
198 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
201 my $id = $U->cstorereq(
202 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
203 { name => $setting, org_unit => $orgid } );
205 $logger->debug("Retrieved setting $id in org unit setting delete");
207 my $s = $U->cstorereq(
208 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
210 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
224 __PACKAGE__->register_method(
225 method => "update_patron",
226 api_name => "open-ils.actor.patron.update",);
229 my( $self, $client, $user_session, $patron ) = @_;
231 my $session = $apputils->start_db_session();
235 $logger->info("Creating new patron...") if $patron->isnew;
236 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
238 my( $user_obj, $evt ) = $U->checkses($user_session);
241 $evt = check_group_perm($session, $user_obj, $patron);
245 # $new_patron is the patron in progress. $patron is the original patron
246 # passed in with the method. new_patron will change as the components
247 # of patron are added/updated.
251 # unflesh the real items on the patron
252 $patron->card( $patron->card->id ) if(ref($patron->card));
253 $patron->billing_address( $patron->billing_address->id )
254 if(ref($patron->billing_address));
255 $patron->mailing_address( $patron->mailing_address->id )
256 if(ref($patron->mailing_address));
258 # create/update the patron first so we can use his id
259 if($patron->isnew()) {
260 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
262 } else { $new_patron = $patron; }
264 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
267 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
270 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
273 # re-update the patron if anything has happened to him during this process
274 if($new_patron->ischanged()) {
275 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
279 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
282 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
285 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
288 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
291 if(!$patron->isnew) {
292 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
295 $apputils->commit_db_session($session);
296 my $fuser = flesh_user($new_patron->id());
299 # Log the new and old patron for investigation
300 $logger->info("$user_session updating patron object. orig patron object = ".
301 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
311 return new_flesh_user($id, [
314 "standing_penalties",
318 "stat_cat_entries" ] );
326 # clone and clear stuff that would break the database
330 my $new_patron = $patron->clone;
332 $new_patron->clear_billing_address();
333 $new_patron->clear_mailing_address();
334 $new_patron->clear_addresses();
335 $new_patron->clear_card();
336 $new_patron->clear_cards();
337 $new_patron->clear_id();
338 $new_patron->clear_isnew();
339 $new_patron->clear_ischanged();
340 $new_patron->clear_isdeleted();
341 $new_patron->clear_stat_cat_entries();
342 $new_patron->clear_permissions();
343 $new_patron->clear_standing_penalties();
353 my $user_obj = shift;
355 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
356 return (undef, $evt) if $evt;
358 my $ex = $session->request(
359 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
361 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
364 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
366 my $id = $session->request(
367 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
368 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
370 $logger->info("Successfully created new user [$id] in DB");
372 return ( $session->request(
373 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
377 sub check_group_perm {
378 my( $session, $requestor, $patron ) = @_;
381 # first let's see if the requestor has
382 # priveleges to update this user in any way
383 if( ! $patron->isnew ) {
384 my $p = $session->request(
385 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
387 # If we are the requestor (trying to update our own account)
388 # and we are not trying to change our profile, we're good
389 if( $p->id == $requestor->id and
390 $p->profile == $patron->profile ) {
395 $evt = group_perm_failed($session, $requestor, $p);
399 # They are allowed to edit this patron.. can they put the
400 # patron into the group requested?
401 $evt = group_perm_failed($session, $requestor, $patron);
407 sub group_perm_failed {
408 my( $session, $requestor, $patron ) = @_;
412 my $grpid = $patron->profile;
416 $logger->debug("user update looking for group perm for group $grpid");
417 $grp = $session->request(
418 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
419 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
421 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
423 $logger->info("user update checking perm $perm on user ".
424 $requestor->id." for update/create on user username=".$patron->usrname);
426 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
434 my( $session, $patron, $user_obj, $noperm) = @_;
436 $logger->info("Updating patron ".$patron->id." in DB");
441 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
442 return (undef, $evt) if $evt;
445 # update the password by itself to avoid the password protection magic
446 if( $patron->passwd ) {
447 my $s = $session->request(
448 'open-ils.storage.direct.actor.user.remote_update',
449 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
450 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
451 $patron->clear_passwd;
454 if(!$patron->ident_type) {
455 $patron->clear_ident_type;
456 $patron->clear_ident_value;
459 $evt = verify_last_xact($session, $patron);
460 return (undef, $evt) if $evt;
462 my $stat = $session->request(
463 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
464 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
469 sub verify_last_xact {
470 my( $session, $patron ) = @_;
471 return undef unless $patron->id and $patron->id > 0;
472 my $p = $session->request(
473 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
474 my $xact = $p->last_xact_id;
475 return undef unless $xact;
476 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
477 return OpenILS::Event->new('XACT_COLLISION')
478 if $xact != $patron->last_xact_id;
483 sub _check_dup_ident {
484 my( $session, $patron ) = @_;
486 return undef unless $patron->ident_value;
489 ident_type => $patron->ident_type,
490 ident_value => $patron->ident_value,
493 $logger->debug("patron update searching for dup ident values: " .
494 $patron->ident_type . ':' . $patron->ident_value);
496 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
498 my $dups = $session->request(
499 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
502 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
509 sub _add_update_addresses {
513 my $new_patron = shift;
517 my $current_id; # id of the address before creation
519 for my $address (@{$patron->addresses()}) {
521 next unless ref $address;
522 $current_id = $address->id();
524 if( $patron->billing_address() and
525 $patron->billing_address() == $current_id ) {
526 $logger->info("setting billing addr to $current_id");
527 $new_patron->billing_address($address->id());
528 $new_patron->ischanged(1);
531 if( $patron->mailing_address() and
532 $patron->mailing_address() == $current_id ) {
533 $new_patron->mailing_address($address->id());
534 $logger->info("setting mailing addr to $current_id");
535 $new_patron->ischanged(1);
539 if($address->isnew()) {
541 $address->usr($new_patron->id());
543 ($address, $evt) = _add_address($session,$address);
544 return (undef, $evt) if $evt;
546 # we need to get the new id
547 if( $patron->billing_address() and
548 $patron->billing_address() == $current_id ) {
549 $new_patron->billing_address($address->id());
550 $logger->info("setting billing addr to $current_id");
551 $new_patron->ischanged(1);
554 if( $patron->mailing_address() and
555 $patron->mailing_address() == $current_id ) {
556 $new_patron->mailing_address($address->id());
557 $logger->info("setting mailing addr to $current_id");
558 $new_patron->ischanged(1);
561 } elsif($address->ischanged() ) {
563 ($address, $evt) = _update_address($session, $address);
564 return (undef, $evt) if $evt;
566 } elsif($address->isdeleted() ) {
568 if( $address->id() == $new_patron->mailing_address() ) {
569 $new_patron->clear_mailing_address();
570 ($new_patron, $evt) = _update_patron($session, $new_patron);
571 return (undef, $evt) if $evt;
574 if( $address->id() == $new_patron->billing_address() ) {
575 $new_patron->clear_billing_address();
576 ($new_patron, $evt) = _update_patron($session, $new_patron);
577 return (undef, $evt) if $evt;
580 $evt = _delete_address($session, $address);
581 return (undef, $evt) if $evt;
585 return ( $new_patron, undef );
589 # adds an address to the db and returns the address with new id
591 my($session, $address) = @_;
592 $address->clear_id();
594 $logger->info("Creating new address at street ".$address->street1);
596 # put the address into the database
597 my $id = $session->request(
598 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
599 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
602 return ($address, undef);
606 sub _update_address {
607 my( $session, $address ) = @_;
609 $logger->info("Updating address ".$address->id." in the DB");
611 my $stat = $session->request(
612 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
614 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
615 return ($address, undef);
620 sub _add_update_cards {
624 my $new_patron = shift;
628 my $virtual_id; #id of the card before creation
629 for my $card (@{$patron->cards()}) {
631 $card->usr($new_patron->id());
633 if(ref($card) and $card->isnew()) {
635 $virtual_id = $card->id();
636 ( $card, $evt ) = _add_card($session,$card);
637 return (undef, $evt) if $evt;
639 #if(ref($patron->card)) { $patron->card($patron->card->id); }
640 if($patron->card() == $virtual_id) {
641 $new_patron->card($card->id());
642 $new_patron->ischanged(1);
645 } elsif( ref($card) and $card->ischanged() ) {
646 $evt = _update_card($session, $card);
647 return (undef, $evt) if $evt;
651 return ( $new_patron, undef );
655 # adds an card to the db and returns the card with new id
657 my( $session, $card ) = @_;
660 $logger->info("Adding new patron card ".$card->barcode);
662 my $id = $session->request(
663 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
664 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
665 $logger->info("Successfully created patron card $id");
668 return ( $card, undef );
672 # returns event on error. returns undef otherwise
674 my( $session, $card ) = @_;
675 $logger->info("Updating patron card ".$card->id);
677 my $stat = $session->request(
678 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
679 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
686 # returns event on error. returns undef otherwise
687 sub _delete_address {
688 my( $session, $address ) = @_;
690 $logger->info("Deleting address ".$address->id." from DB");
692 my $stat = $session->request(
693 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
695 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
701 sub _add_survey_responses {
702 my ($session, $patron, $new_patron) = @_;
704 $logger->info( "Updating survey responses for patron ".$new_patron->id );
706 my $responses = $patron->survey_responses;
710 $_->usr($new_patron->id) for (@$responses);
712 my $evt = $U->simplereq( "open-ils.circ",
713 "open-ils.circ.survey.submit.user_id", $responses );
715 return (undef, $evt) if defined($U->event_code($evt));
719 return ( $new_patron, undef );
723 sub _create_stat_maps {
725 my($session, $user_session, $patron, $new_patron) = @_;
727 my $maps = $patron->stat_cat_entries();
729 for my $map (@$maps) {
731 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
733 if ($map->isdeleted()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
736 } elsif ($map->isnew()) {
737 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
742 $map->target_usr($new_patron->id);
745 $logger->info("Updating stat entry with method $method and map $map");
747 my $stat = $session->request($method, $map)->gather(1);
748 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
752 return ($new_patron, undef);
755 sub _create_perm_maps {
757 my($session, $user_session, $patron, $new_patron) = @_;
759 my $maps = $patron->permissions;
761 for my $map (@$maps) {
763 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
764 if ($map->isdeleted()) {
765 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
766 } elsif ($map->isnew()) {
767 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
772 $map->usr($new_patron->id);
774 #warn( "Updating permissions with method $method and session $user_session and map $map" );
775 $logger->info( "Updating permissions with method $method and map $map" );
777 my $stat = $session->request($method, $map)->gather(1);
778 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
782 return ($new_patron, undef);
786 __PACKAGE__->register_method(
787 method => "set_user_work_ous",
788 api_name => "open-ils.actor.user.work_ous.update",
791 sub set_user_work_ous {
797 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
800 my $session = $apputils->start_db_session();
802 for my $map (@$maps) {
804 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
805 if ($map->isdeleted()) {
806 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
807 } elsif ($map->isnew()) {
808 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
812 #warn( "Updating permissions with method $method and session $ses and map $map" );
813 $logger->info( "Updating work_ou map with method $method and map $map" );
815 my $stat = $session->request($method, $map)->gather(1);
816 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
820 $apputils->commit_db_session($session);
822 return scalar(@$maps);
826 __PACKAGE__->register_method(
827 method => "set_user_perms",
828 api_name => "open-ils.actor.user.permissions.update",
837 my $session = $apputils->start_db_session();
839 my( $user_obj, $evt ) = $U->checkses($ses);
842 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
845 $all = 1 if ($user_obj->super_user());
846 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
848 for my $map (@$maps) {
850 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
851 if ($map->isdeleted()) {
852 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
853 } elsif ($map->isnew()) {
854 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
858 next if (!$all || !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
860 #warn( "Updating permissions with method $method and session $ses and map $map" );
861 $logger->info( "Updating permissions with method $method and map $map" );
863 my $stat = $session->request($method, $map)->gather(1);
864 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
868 $apputils->commit_db_session($session);
870 return scalar(@$maps);
874 sub _create_standing_penalties {
876 my($session, $user_session, $patron, $new_patron) = @_;
878 my $maps = $patron->standing_penalties;
881 for my $map (@$maps) {
883 if ($map->isdeleted()) {
884 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
885 } elsif ($map->isnew()) {
886 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
892 $map->usr($new_patron->id);
894 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
896 my $stat = $session->request($method, $map)->gather(1);
897 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
900 return ($new_patron, undef);
905 __PACKAGE__->register_method(
906 method => "search_username",
907 api_name => "open-ils.actor.user.search.username",
910 sub search_username {
911 my($self, $client, $username) = @_;
912 return new_editor()->search_actor_user({usrname=>$username});
918 __PACKAGE__->register_method(
919 method => "user_retrieve_by_barcode",
921 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
923 sub user_retrieve_by_barcode {
924 my($self, $client, $user_session, $barcode) = @_;
926 $logger->debug("Searching for user with barcode $barcode");
927 my ($user_obj, $evt) = $apputils->checkses($user_session);
930 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
932 "open-ils.cstore.direct.actor.card.search.atomic",
933 { barcode => $barcode }
936 if(!$card || !$card->[0]) {
937 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
941 my $user = flesh_user($card->usr());
943 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
946 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
953 __PACKAGE__->register_method(
954 method => "get_user_by_id",
955 api_name => "open-ils.actor.user.retrieve",);
958 my ($self, $client, $auth, $id) = @_;
959 my $e = new_editor(authtoken=>$auth);
960 return $e->event unless $e->checkauth;
961 my $user = $e->retrieve_actor_user($id)
963 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
969 __PACKAGE__->register_method(
970 method => "get_org_types",
971 api_name => "open-ils.actor.org_types.retrieve",);
974 return $U->get_org_types();
979 __PACKAGE__->register_method(
980 method => "get_user_ident_types",
981 api_name => "open-ils.actor.user.ident_types.retrieve",
984 sub get_user_ident_types {
985 return $ident_types if $ident_types;
986 return $ident_types =
987 new_editor()->retrieve_all_config_identification_type();
993 __PACKAGE__->register_method(
994 method => "get_org_unit",
995 api_name => "open-ils.actor.org_unit.retrieve",
999 my( $self, $client, $user_session, $org_id ) = @_;
1000 my $e = new_editor(authtoken => $user_session);
1002 return $e->event unless $e->checkauth;
1003 $org_id = $e->requestor->ws_ou;
1005 my $o = $e->retrieve_actor_org_unit($org_id)
1006 or return $e->event;
1010 __PACKAGE__->register_method(
1011 method => "search_org_unit",
1012 api_name => "open-ils.actor.org_unit_list.search",
1015 sub search_org_unit {
1017 my( $self, $client, $field, $value ) = @_;
1019 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1021 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1022 { $field => $value } );
1028 # build the org tree
1030 __PACKAGE__->register_method(
1031 method => "get_org_tree",
1032 api_name => "open-ils.actor.org_tree.retrieve",
1034 note => "Returns the entire org tree structure",
1038 my( $self, $client) = @_;
1039 return $U->get_org_tree();
1043 __PACKAGE__->register_method(
1044 method => "get_org_descendants",
1045 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1048 # depth is optional. org_unit is the id
1049 sub get_org_descendants {
1050 my( $self, $client, $org_unit, $depth ) = @_;
1052 if(ref $org_unit eq 'ARRAY') {
1055 for my $i (0..scalar(@$org_unit)-1) {
1056 my $list = $U->simple_scalar_request(
1058 "open-ils.storage.actor.org_unit.descendants.atomic",
1059 $org_unit->[$i], $depth->[$i] );
1060 push(@trees, $U->build_org_tree($list));
1065 my $orglist = $apputils->simple_scalar_request(
1067 "open-ils.storage.actor.org_unit.descendants.atomic",
1068 $org_unit, $depth );
1069 return $U->build_org_tree($orglist);
1074 __PACKAGE__->register_method(
1075 method => "get_org_ancestors",
1076 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1079 # depth is optional. org_unit is the id
1080 sub get_org_ancestors {
1081 my( $self, $client, $org_unit, $depth ) = @_;
1082 my $orglist = $apputils->simple_scalar_request(
1084 "open-ils.storage.actor.org_unit.ancestors.atomic",
1085 $org_unit, $depth );
1086 return $U->build_org_tree($orglist);
1090 __PACKAGE__->register_method(
1091 method => "get_standings",
1092 api_name => "open-ils.actor.standings.retrieve"
1097 return $user_standings if $user_standings;
1098 return $user_standings =
1099 $apputils->simple_scalar_request(
1101 "open-ils.cstore.direct.config.standing.search.atomic",
1102 { id => { "!=" => undef } }
1108 __PACKAGE__->register_method(
1109 method => "get_my_org_path",
1110 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1113 sub get_my_org_path {
1114 my( $self, $client, $auth, $org_id ) = @_;
1115 my $e = new_editor(authtoken=>$auth);
1116 return $e->event unless $e->checkauth;
1117 $org_id = $e->requestor->ws_ou unless defined $org_id;
1119 return $apputils->simple_scalar_request(
1121 "open-ils.storage.actor.org_unit.full_path.atomic",
1126 __PACKAGE__->register_method(
1127 method => "patron_adv_search",
1128 api_name => "open-ils.actor.patron.search.advanced" );
1129 sub patron_adv_search {
1130 my( $self, $client, $auth, $search_hash,
1131 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1133 my $e = new_editor(authtoken=>$auth);
1134 return $e->event unless $e->checkauth;
1135 return $e->event unless $e->allowed('VIEW_USER');
1136 return $U->storagereq(
1137 "open-ils.storage.actor.user.crazy_search", $search_hash,
1138 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1142 __PACKAGE__->register_method(
1143 method => "update_passwd",
1145 api_name => "open-ils.actor.user.password.update");
1147 __PACKAGE__->register_method(
1148 method => "update_passwd",
1149 api_name => "open-ils.actor.user.username.update");
1151 __PACKAGE__->register_method(
1152 method => "update_passwd",
1153 api_name => "open-ils.actor.user.email.update");
1156 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1157 my $e = new_editor(xact=>1, authtoken=>$auth);
1158 return $e->die_event unless $e->checkauth;
1160 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1161 or return $e->die_event;
1162 my $api = $self->api_name;
1164 if( $api =~ /password/o ) {
1166 # make sure the original password matches the in-database password
1167 return OpenILS::Event->new('INCORRECT_PASSWORD')
1168 if md5_hex($orig_pw) ne $db_user->passwd;
1169 $db_user->passwd($new_val);
1173 # if we don't clear the password, the user will be updated with
1174 # a hashed version of the hashed version of their password
1175 $db_user->clear_passwd;
1177 if( $api =~ /username/o ) {
1179 # make sure no one else has this username
1180 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1181 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1182 $db_user->usrname($new_val);
1184 } elsif( $api =~ /email/o ) {
1185 $db_user->email($new_val);
1189 $e->update_actor_user($db_user) or return $e->die_event;
1197 __PACKAGE__->register_method(
1198 method => "check_user_perms",
1199 api_name => "open-ils.actor.user.perm.check",
1200 notes => <<" NOTES");
1201 Takes a login session, user id, an org id, and an array of perm type strings. For each
1202 perm type, if the user does *not* have the given permission it is added
1203 to a list which is returned from the method. If all permissions
1204 are allowed, an empty list is returned
1205 if the logged in user does not match 'user_id', then the logged in user must
1206 have VIEW_PERMISSION priveleges.
1209 sub check_user_perms {
1210 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1212 my( $staff, $evt ) = $apputils->checkses($login_session);
1213 return $evt if $evt;
1215 if($staff->id ne $user_id) {
1216 if( $evt = $apputils->check_perms(
1217 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1223 for my $perm (@$perm_types) {
1224 if($apputils->check_perms($user_id, $org_id, $perm)) {
1225 push @not_allowed, $perm;
1229 return \@not_allowed
1232 __PACKAGE__->register_method(
1233 method => "check_user_perms2",
1234 api_name => "open-ils.actor.user.perm.check.multi_org",
1236 Checks the permissions on a list of perms and orgs for a user
1237 @param authtoken The login session key
1238 @param user_id The id of the user to check
1239 @param orgs The array of org ids
1240 @param perms The array of permission names
1241 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1242 if the logged in user does not match 'user_id', then the logged in user must
1243 have VIEW_PERMISSION priveleges.
1246 sub check_user_perms2 {
1247 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1249 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1250 $authtoken, $user_id, 'VIEW_PERMISSION' );
1251 return $evt if $evt;
1254 for my $org (@$orgs) {
1255 for my $perm (@$perms) {
1256 if($apputils->check_perms($user_id, $org, $perm)) {
1257 push @not_allowed, [ $org, $perm ];
1262 return \@not_allowed
1266 __PACKAGE__->register_method(
1267 method => 'check_user_perms3',
1268 api_name => 'open-ils.actor.user.perm.highest_org',
1270 Returns the highest org unit id at which a user has a given permission
1271 If the requestor does not match the target user, the requestor must have
1272 'VIEW_PERMISSION' rights at the home org unit of the target user
1273 @param authtoken The login session key
1274 @param userid The id of the user in question
1275 @param perm The permission to check
1276 @return The org unit highest in the org tree within which the user has
1277 the requested permission
1280 sub check_user_perms3 {
1281 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1283 my( $staff, $target, $org, $evt );
1285 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1286 $authtoken, $userid, 'VIEW_PERMISSION' );
1287 return $evt if $evt;
1289 my $tree = $U->get_org_tree();
1290 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1294 __PACKAGE__->register_method(
1295 method => 'check_user_work_perms',
1296 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1300 Returns a set of org units which represent the highest orgs in
1301 the org tree where the user has the requested permission. The
1302 purpose of this method is to return the smallest set of org units
1303 which represent the full expanse of the user's ability to perform
1304 the requested action. The user whose perms this method should
1305 check is implied by the authtoken. /,
1307 {desc => 'authtoken', type => 'string'},
1308 {desc => 'permission name', type => 'string'},
1309 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1311 return => {desc => 'An array of org IDs'}
1315 sub check_user_work_perms {
1316 my($self, $conn, $auth, $perm, $options) = @_;
1317 my $e = new_editor(authtoken=>$auth);
1318 return $e->event unless $e->checkauth;
1319 return $U->find_highest_work_orgs($e, $perm, $options);
1322 __PACKAGE__->register_method(
1323 method => 'check_user_perms4',
1324 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1326 Returns the highest org unit id at which a user has a given permission
1327 If the requestor does not match the target user, the requestor must have
1328 'VIEW_PERMISSION' rights at the home org unit of the target user
1329 @param authtoken The login session key
1330 @param userid The id of the user in question
1331 @param perms An array of perm names to check
1332 @return An array of orgId's representing the org unit
1333 highest in the org tree within which the user has the requested permission
1334 The arrah of orgId's has matches the order of the perms array
1337 sub check_user_perms4 {
1338 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1340 my( $staff, $target, $org, $evt );
1342 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1343 $authtoken, $userid, 'VIEW_PERMISSION' );
1344 return $evt if $evt;
1347 return [] unless ref($perms);
1348 my $tree = $U->get_org_tree();
1350 for my $p (@$perms) {
1351 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1359 __PACKAGE__->register_method(
1360 method => "user_fines_summary",
1361 api_name => "open-ils.actor.user.fines.summary",
1363 notes => <<" NOTES");
1364 Returns a short summary of the users total open fines, excluding voided fines
1365 Params are login_session, user_id
1366 Returns a 'mous' object.
1369 sub user_fines_summary {
1370 my( $self, $client, $auth, $user_id ) = @_;
1371 my $e = new_editor(authtoken=>$auth);
1372 return $e->event unless $e->checkauth;
1373 my $user = $e->retrieve_actor_user($user_id)
1374 or return $e->event;
1376 if( $user_id ne $e->requestor->id ) {
1377 return $e->event unless
1378 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1381 # run this inside a transaction to prevent replication delay errors
1382 my $ses = $U->start_db_session();
1383 my $s = $ses->request(
1384 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1385 $U->rollback_db_session($ses);
1392 __PACKAGE__->register_method(
1393 method => "user_transactions",
1394 api_name => "open-ils.actor.user.transactions",
1395 notes => <<" NOTES");
1396 Returns a list of open user transactions (mbts objects);
1397 Params are login_session, user_id
1398 Optional third parameter is the transactions type. defaults to all
1401 __PACKAGE__->register_method(
1402 method => "user_transactions",
1403 api_name => "open-ils.actor.user.transactions.have_charge",
1404 notes => <<" NOTES");
1405 Returns a list of all open user transactions (mbts objects) that have an initial charge
1406 Params are login_session, user_id
1407 Optional third parameter is the transactions type. defaults to all
1410 __PACKAGE__->register_method(
1411 method => "user_transactions",
1412 api_name => "open-ils.actor.user.transactions.have_balance",
1413 notes => <<" NOTES");
1414 Returns a list of all open user transactions (mbts objects) that have a balance
1415 Params are login_session, user_id
1416 Optional third parameter is the transactions type. defaults to all
1419 __PACKAGE__->register_method(
1420 method => "user_transactions",
1421 api_name => "open-ils.actor.user.transactions.fleshed",
1422 notes => <<" NOTES");
1423 Returns an object/hash of transaction, circ, title where transaction = an open
1424 user transactions (mbts objects), circ is the attached circluation, and title
1425 is the title the circ points to
1426 Params are login_session, user_id
1427 Optional third parameter is the transactions type. defaults to all
1430 __PACKAGE__->register_method(
1431 method => "user_transactions",
1432 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1433 notes => <<" NOTES");
1434 Returns an object/hash of transaction, circ, title where transaction = an open
1435 user transactions that has an initial charge (mbts objects), circ is the
1436 attached circluation, and title is the title the circ points to
1437 Params are login_session, user_id
1438 Optional third parameter is the transactions type. defaults to all
1441 __PACKAGE__->register_method(
1442 method => "user_transactions",
1443 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1444 notes => <<" NOTES");
1445 Returns an object/hash of transaction, circ, title where transaction = an open
1446 user transaction that has a balance (mbts objects), circ is the attached
1447 circluation, and title is the title the circ points to
1448 Params are login_session, user_id
1449 Optional third parameter is the transaction type. defaults to all
1452 __PACKAGE__->register_method(
1453 method => "user_transactions",
1454 api_name => "open-ils.actor.user.transactions.count",
1455 notes => <<" NOTES");
1456 Returns an object/hash of transaction, circ, title where transaction = an open
1457 user transactions (mbts objects), circ is the attached circluation, and title
1458 is the title the circ points to
1459 Params are login_session, user_id
1460 Optional third parameter is the transactions type. defaults to all
1463 __PACKAGE__->register_method(
1464 method => "user_transactions",
1465 api_name => "open-ils.actor.user.transactions.have_charge.count",
1466 notes => <<" NOTES");
1467 Returns an object/hash of transaction, circ, title where transaction = an open
1468 user transactions that has an initial charge (mbts objects), circ is the
1469 attached circluation, and title is the title the circ points to
1470 Params are login_session, user_id
1471 Optional third parameter is the transactions type. defaults to all
1474 __PACKAGE__->register_method(
1475 method => "user_transactions",
1476 api_name => "open-ils.actor.user.transactions.have_balance.count",
1477 notes => <<" NOTES");
1478 Returns an object/hash of transaction, circ, title where transaction = an open
1479 user transaction that has a balance (mbts objects), circ is the attached
1480 circluation, and title is the title the circ points to
1481 Params are login_session, user_id
1482 Optional third parameter is the transaction type. defaults to all
1485 __PACKAGE__->register_method(
1486 method => "user_transactions",
1487 api_name => "open-ils.actor.user.transactions.have_balance.total",
1488 notes => <<" NOTES");
1489 Returns an object/hash of transaction, circ, title where transaction = an open
1490 user transaction that has a balance (mbts objects), circ is the attached
1491 circluation, and title is the title the circ points to
1492 Params are login_session, user_id
1493 Optional third parameter is the transaction type. defaults to all
1498 sub user_transactions {
1499 my( $self, $client, $login_session, $user_id, $type ) = @_;
1501 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1502 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1503 return $evt if $evt;
1505 my $api = $self->api_name();
1509 if(defined($type)) { @xact = (xact_type => $type);
1511 } else { @xact = (); }
1514 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1515 ->run($login_session => $user_id => $type);
1517 if($api =~ /have_charge/o) {
1519 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1521 } elsif($api =~ /have_balance/o) {
1523 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1526 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1530 if($api =~ /total/o) {
1532 for my $t (@$trans) {
1533 $total += $t->balance_owed;
1536 $logger->debug("Total balance owed by user $user_id: $total");
1540 if($api =~ /count/o) { return scalar @$trans; }
1541 if($api !~ /fleshed/o) { return $trans; }
1544 for my $t (@$trans) {
1546 if( $t->xact_type ne 'circulation' ) {
1547 push @resp, {transaction => $t};
1551 my $circ = $apputils->simple_scalar_request(
1553 "open-ils.cstore.direct.action.circulation.retrieve",
1558 my $title = $apputils->simple_scalar_request(
1560 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1561 $circ->target_copy );
1565 my $u = OpenILS::Utils::ModsParser->new();
1566 $u->start_mods_batch($title->marc());
1567 my $mods = $u->finish_mods_batch();
1568 $mods->doc_id($title->id) if $mods;
1570 push @resp, {transaction => $t, circ => $circ, record => $mods };
1578 __PACKAGE__->register_method(
1579 method => "user_transaction_retrieve",
1580 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1582 notes => <<" NOTES");
1583 Returns a fleshedtransaction record
1585 __PACKAGE__->register_method(
1586 method => "user_transaction_retrieve",
1587 api_name => "open-ils.actor.user.transaction.retrieve",
1589 notes => <<" NOTES");
1590 Returns a transaction record
1592 sub user_transaction_retrieve {
1593 my( $self, $client, $login_session, $bill_id ) = @_;
1595 # XXX I think I'm deprecated... make sure
1597 my $trans = $apputils->simple_scalar_request(
1599 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1603 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1604 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1605 return $evt if $evt;
1607 my $api = $self->api_name();
1608 if($api !~ /fleshed/o) { return $trans; }
1610 if( $trans->xact_type ne 'circulation' ) {
1611 $logger->debug("Returning non-circ transaction");
1612 return {transaction => $trans};
1615 my $circ = $apputils->simple_scalar_request(
1617 "open-ils..direct.action.circulation.retrieve",
1620 return {transaction => $trans} unless $circ;
1621 $logger->debug("Found the circ transaction");
1623 my $title = $apputils->simple_scalar_request(
1625 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1626 $circ->target_copy );
1628 return {transaction => $trans, circ => $circ } unless $title;
1629 $logger->debug("Found the circ title");
1633 my $u = OpenILS::Utils::ModsParser->new();
1634 $u->start_mods_batch($title->marc());
1635 $mods = $u->finish_mods_batch();
1637 if ($title->id == OILS_PRECAT_RECORD) {
1638 my $copy = $apputils->simple_scalar_request(
1640 "open-ils.cstore.direct.asset.copy.retrieve",
1641 $circ->target_copy );
1643 $mods = new Fieldmapper::metabib::virtual_record;
1644 $mods->doc_id(OILS_PRECAT_RECORD);
1645 $mods->title($copy->dummy_title);
1646 $mods->author($copy->dummy_author);
1650 $logger->debug("MODSized the circ title");
1652 return {transaction => $trans, circ => $circ, record => $mods };
1656 __PACKAGE__->register_method(
1657 method => "hold_request_count",
1658 api_name => "open-ils.actor.user.hold_requests.count",
1661 notes => <<" NOTES");
1662 Returns hold ready/total counts
1664 sub hold_request_count {
1665 my( $self, $client, $login_session, $userid ) = @_;
1667 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1668 $login_session, $userid, 'VIEW_HOLD' );
1669 return $evt if $evt;
1672 my $holds = $apputils->simple_scalar_request(
1674 "open-ils.cstore.direct.action.hold_request.search.atomic",
1677 fulfillment_time => {"=" => undef },
1678 cancel_time => undef,
1683 for my $h (@$holds) {
1684 next unless $h->capture_time and $h->current_copy;
1686 my $copy = $apputils->simple_scalar_request(
1688 "open-ils.cstore.direct.asset.copy.retrieve",
1692 if ($copy and $copy->status == 8) {
1697 return { total => scalar(@$holds), ready => scalar(@ready) };
1701 __PACKAGE__->register_method(
1702 method => "checkedout_count",
1703 api_name => "open-ils.actor.user.checked_out.count__",
1705 notes => <<" NOTES");
1706 Returns a transaction record
1710 sub checkedout_count {
1711 my( $self, $client, $login_session, $userid ) = @_;
1713 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1714 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1715 return $evt if $evt;
1717 my $circs = $apputils->simple_scalar_request(
1719 "open-ils.cstore.direct.action.circulation.search.atomic",
1720 { usr => $userid, stop_fines => undef }
1721 #{ usr => $userid, checkin_time => {"=" => undef } }
1724 my $parser = DateTime::Format::ISO8601->new;
1727 for my $c (@$circs) {
1728 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1729 my $due = $due_dt->epoch;
1731 if ($due < DateTime->today->epoch) {
1736 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1740 __PACKAGE__->register_method(
1741 method => "checked_out",
1742 api_name => "open-ils.actor.user.checked_out",
1746 Returns a structure of circulations objects sorted by
1747 out, overdue, lost, claims_returned, long_overdue.
1748 A list of IDs are returned of each type.
1749 lost, long_overdue, and claims_returned circ will not
1750 be "finished" (there is an outstanding balance or some
1751 other pending action on the circ).
1753 The .count method also includes a 'total' field which
1754 sums all "open" circs
1758 __PACKAGE__->register_method(
1759 method => "checked_out",
1760 api_name => "open-ils.actor.user.checked_out.count",
1763 signature => q/@see open-ils.actor.user.checked_out/
1767 my( $self, $conn, $auth, $userid ) = @_;
1769 my $e = new_editor(authtoken=>$auth);
1770 return $e->event unless $e->checkauth;
1772 if( $userid ne $e->requestor->id ) {
1773 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1776 my $count = $self->api_name =~ /count/;
1777 return _checked_out( $count, $e, $userid );
1781 my( $iscount, $e, $userid ) = @_;
1784 my $meth = 'open-ils.storage.actor.user.checked_out';
1785 $meth = "$meth.count" if $iscount;
1786 return $U->storagereq($meth, $userid);
1788 # XXX Old code - moved to storage
1789 #------------------------------------------------------------------------------
1790 #------------------------------------------------------------------------------
1791 my $circs = $e->search_action_circulation(
1792 { usr => $userid, checkin_time => undef });
1794 my $parser = DateTime::Format::ISO8601->new;
1796 # split the circs up into overdue and not-overdue circs
1798 for my $c (@$circs) {
1799 if( $c->due_date ) {
1800 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1801 my $due = $due_dt->epoch;
1802 if ($due < DateTime->today->epoch) {
1812 my( @open, @od, @lost, @cr, @lo );
1814 while (my $c = shift(@out)) {
1815 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1816 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1817 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1818 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1821 while (my $c = shift(@overdue)) {
1822 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1823 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1824 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1825 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1830 total => @open + @od + @lost + @cr + @lo,
1831 out => scalar(@open),
1832 overdue => scalar(@od),
1833 lost => scalar(@lost),
1834 claims_returned => scalar(@cr),
1835 long_overdue => scalar(@lo)
1843 claims_returned => \@cr,
1844 long_overdue => \@lo
1849 sub _checked_out_WHAT {
1850 my( $iscount, $e, $userid ) = @_;
1852 my $circs = $e->search_action_circulation(
1853 { usr => $userid, stop_fines => undef });
1855 my $mcircs = $e->search_action_circulation(
1858 checkin_time => undef,
1859 xact_finish => undef,
1863 push( @$circs, @$mcircs );
1865 my $parser = DateTime::Format::ISO8601->new;
1867 # split the circs up into overdue and not-overdue circs
1869 for my $c (@$circs) {
1870 if( $c->due_date ) {
1871 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1872 my $due = $due_dt->epoch;
1873 if ($due < DateTime->today->epoch) {
1874 push @overdue, $c->id;
1883 # grab all of the lost, claims-returned, and longoverdue circs
1884 #my $open = $e->search_action_circulation(
1885 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1888 # these items have stop_fines, but no xact_finish, so money
1889 # is owed on them and they have not been checked in
1890 my $open = $e->search_action_circulation(
1893 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1894 xact_finish => undef,
1895 checkin_time => undef,
1900 my( @lost, @cr, @lo );
1901 for my $c (@$open) {
1902 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1903 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1904 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1910 total => @$circs + @lost + @cr + @lo,
1911 out => scalar(@out),
1912 overdue => scalar(@overdue),
1913 lost => scalar(@lost),
1914 claims_returned => scalar(@cr),
1915 long_overdue => scalar(@lo)
1921 overdue => \@overdue,
1923 claims_returned => \@cr,
1924 long_overdue => \@lo
1930 __PACKAGE__->register_method(
1931 method => "checked_in_with_fines",
1932 api_name => "open-ils.actor.user.checked_in_with_fines",
1935 signature => q/@see open-ils.actor.user.checked_out/
1937 sub checked_in_with_fines {
1938 my( $self, $conn, $auth, $userid ) = @_;
1940 my $e = new_editor(authtoken=>$auth);
1941 return $e->event unless $e->checkauth;
1943 if( $userid ne $e->requestor->id ) {
1944 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1947 # money is owed on these items and they are checked in
1948 my $open = $e->search_action_circulation(
1951 xact_finish => undef,
1952 checkin_time => { "!=" => undef },
1957 my( @lost, @cr, @lo );
1958 for my $c (@$open) {
1959 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1960 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1961 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1966 claims_returned => \@cr,
1967 long_overdue => \@lo
1979 __PACKAGE__->register_method(
1980 method => "user_transaction_history",
1981 api_name => "open-ils.actor.user.transactions.history",
1983 notes => <<" NOTES");
1984 Returns a list of billable transaction ids for a user, optionally by type
1986 __PACKAGE__->register_method(
1987 method => "user_transaction_history",
1988 api_name => "open-ils.actor.user.transactions.history.have_charge",
1990 notes => <<" NOTES");
1991 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1993 __PACKAGE__->register_method(
1994 method => "user_transaction_history",
1995 api_name => "open-ils.actor.user.transactions.history.have_balance",
1998 notes => <<" NOTES");
1999 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2001 __PACKAGE__->register_method(
2002 method => "user_transaction_history",
2003 api_name => "open-ils.actor.user.transactions.history.still_open",
2005 notes => <<" NOTES");
2006 Returns a list of billable transaction ids for a user that are not finished
2008 __PACKAGE__->register_method(
2009 method => "user_transaction_history",
2010 api_name => "open-ils.actor.user.transactions.history.have_bill",
2013 notes => <<" NOTES");
2014 Returns a list of billable transaction ids for a user that has billings
2020 sub _user_transaction_history {
2021 my( $self, $client, $login_session, $user_id, $type ) = @_;
2023 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2024 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2025 return $evt if $evt;
2027 my $api = $self->api_name();
2032 @xact = (xact_type => $type) if(defined($type));
2033 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2034 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2036 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2038 my $trans = $apputils->simple_scalar_request(
2040 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2041 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2043 return [ map { $_->id } @$trans ];
2047 =head SEE APPUTILS.PM
2052 for my $x (@xacts) {
2053 my $s = new Fieldmapper::money::billable_transaction_summary;
2056 $s->xact_start( $x->xact_start );
2057 $s->xact_finish( $x->xact_finish );
2061 for my $b (@{ $x->billings }) {
2062 next if ($U->is_true($b->voided));
2063 $to += ($b->amount * 100);
2064 $lb ||= $b->billing_ts;
2065 if ($b->billing_ts ge $lb) {
2066 $lb = $b->billing_ts;
2067 $s->last_billing_note($b->note);
2068 $s->last_billing_ts($b->billing_ts);
2069 $s->last_billing_type($b->billing_type);
2073 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2077 for my $p (@{ $x->payments }) {
2078 next if ($U->is_true($p->voided));
2079 $tp += ($p->amount * 100);
2080 $lp ||= $p->payment_ts;
2081 if ($p->payment_ts ge $lp) {
2082 $lp = $p->payment_ts;
2083 $s->last_payment_note($p->note);
2084 $s->last_payment_ts($p->payment_ts);
2085 $s->last_payment_type($p->payment_type);
2088 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2090 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2092 $s->xact_type( 'grocery' ) if ($x->grocery);
2093 $s->xact_type( 'circulation' ) if ($x->circulation);
2102 sub user_transaction_history {
2103 my( $self, $conn, $auth, $userid, $type ) = @_;
2105 # run inside of a transaction to prevent replication delays
2106 my $e = new_editor(xact=>1, authtoken=>$auth);
2107 return $e->die_event unless $e->checkauth;
2109 if( $e->requestor->id ne $userid ) {
2110 return $e->die_event
2111 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2114 my $api = $self->api_name;
2115 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2117 my @xacts = @{ $e->search_money_billable_transaction(
2118 [ { usr => $userid, @xact_finish },
2120 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2121 order_by => { mbt => 'xact_start DESC' },
2129 #my @mbts = _make_mbts( @xacts );
2130 my @mbts = $U->make_mbts( @xacts );
2132 if(defined($type)) {
2133 @mbts = grep { $_->xact_type eq $type } @mbts;
2136 if($api =~ /have_balance/o) {
2137 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2140 if($api =~ /have_charge/o) {
2141 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2144 if($api =~ /have_bill/o) {
2145 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2153 __PACKAGE__->register_method(
2154 method => "user_perms",
2155 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2157 notes => <<" NOTES");
2158 Returns a list of permissions
2161 my( $self, $client, $authtoken, $user ) = @_;
2163 my( $staff, $evt ) = $apputils->checkses($authtoken);
2164 return $evt if $evt;
2166 $user ||= $staff->id;
2168 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2172 return $apputils->simple_scalar_request(
2174 "open-ils.storage.permission.user_perms.atomic",
2178 __PACKAGE__->register_method(
2179 method => "retrieve_perms",
2180 api_name => "open-ils.actor.permissions.retrieve",
2181 notes => <<" NOTES");
2182 Returns a list of permissions
2184 sub retrieve_perms {
2185 my( $self, $client ) = @_;
2186 return $apputils->simple_scalar_request(
2188 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2189 { id => { '!=' => undef } }
2193 __PACKAGE__->register_method(
2194 method => "retrieve_groups",
2195 api_name => "open-ils.actor.groups.retrieve",
2196 notes => <<" NOTES");
2197 Returns a list of user groupss
2199 sub retrieve_groups {
2200 my( $self, $client ) = @_;
2201 return new_editor()->retrieve_all_permission_grp_tree();
2204 __PACKAGE__->register_method(
2205 method => "retrieve_org_address",
2206 api_name => "open-ils.actor.org_unit.address.retrieve",
2207 notes => <<' NOTES');
2208 Returns an org_unit address by ID
2209 @param An org_address ID
2211 sub retrieve_org_address {
2212 my( $self, $client, $id ) = @_;
2213 return $apputils->simple_scalar_request(
2215 "open-ils.cstore.direct.actor.org_address.retrieve",
2220 __PACKAGE__->register_method(
2221 method => "retrieve_groups_tree",
2222 api_name => "open-ils.actor.groups.tree.retrieve",
2223 notes => <<" NOTES");
2224 Returns a list of user groups
2226 sub retrieve_groups_tree {
2227 my( $self, $client ) = @_;
2228 return new_editor()->search_permission_grp_tree(
2233 flesh_fields => { pgt => ["children"] },
2234 order_by => { pgt => 'name'}
2241 # turns an org list into an org tree
2243 sub build_group_tree {
2245 my( $self, $grplist) = @_;
2247 return $grplist unless (
2248 ref($grplist) and @$grplist > 1 );
2250 my @list = sort { $a->name cmp $b->name } @$grplist;
2253 for my $grp (@list) {
2255 if ($grp and !defined($grp->parent)) {
2259 my ($parent) = grep { $_->id == $grp->parent} @list;
2261 $parent->children([]) unless defined($parent->children);
2262 push( @{$parent->children}, $grp );
2270 __PACKAGE__->register_method(
2271 method => "add_user_to_groups",
2272 api_name => "open-ils.actor.user.set_groups",
2273 notes => <<" NOTES");
2274 Adds a user to one or more permission groups
2277 sub add_user_to_groups {
2278 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2280 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2281 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2282 return $evt if $evt;
2284 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2285 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2286 return $evt if $evt;
2288 $apputils->simplereq(
2290 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2292 for my $group (@$groups) {
2293 my $link = Fieldmapper::permission::usr_grp_map->new;
2295 $link->usr($userid);
2297 my $id = $apputils->simplereq(
2299 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2305 __PACKAGE__->register_method(
2306 method => "get_user_perm_groups",
2307 api_name => "open-ils.actor.user.get_groups",
2308 notes => <<" NOTES");
2309 Retrieve a user's permission groups.
2313 sub get_user_perm_groups {
2314 my( $self, $client, $authtoken, $userid ) = @_;
2316 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2317 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2318 return $evt if $evt;
2320 return $apputils->simplereq(
2322 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2326 __PACKAGE__->register_method(
2327 method => "get_user_work_ous",
2328 api_name => "open-ils.actor.user.get_work_ous",
2329 notes => <<" NOTES");
2330 Retrieve a user's work org units.
2332 __PACKAGE__->register_method(
2333 method => "get_user_work_ous",
2334 api_name => "open-ils.actor.user.get_work_ous.ids",
2335 notes => <<" NOTES");
2336 Retrieve a user's work org units.
2340 sub get_user_work_ous {
2341 my( $self, $client, $auth, $userid ) = @_;
2342 my $e = new_editor(authtoken=>$auth);
2343 return $e->event unless $e->checkauth;
2344 $userid ||= $e->requestor->id;
2346 if($e->requestor->id != $userid) {
2347 my $user = $e->retrieve_actor_user($userid)
2348 or return $e->event;
2349 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2352 return $e->search_permission_usr_work_ou_map({usr => $userid})
2353 unless $self->api_name =~ /.ids$/;
2355 # client just wants a list of org IDs
2356 return $U->get_user_work_ou_ids($e, $userid);
2362 __PACKAGE__->register_method (
2363 method => 'register_workstation',
2364 api_name => 'open-ils.actor.workstation.register.override',
2365 signature => q/@see open-ils.actor.workstation.register/);
2367 __PACKAGE__->register_method (
2368 method => 'register_workstation',
2369 api_name => 'open-ils.actor.workstation.register',
2371 Registers a new workstion in the system
2372 @param authtoken The login session key
2373 @param name The name of the workstation id
2374 @param owner The org unit that owns this workstation
2375 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2376 if the name is already in use.
2379 sub register_workstation {
2380 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2382 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2383 return $e->die_event unless $e->checkauth;
2384 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2385 my $existing = $e->search_actor_workstation({name => $name})->[0];
2389 if( $self->api_name =~ /override/o ) {
2390 # workstation with the given name exists.
2392 if($owner ne $existing->owning_lib) {
2393 # if necessary, update the owning_lib of the workstation
2395 $logger->info("changing owning lib of workstation ".$existing->id.
2396 " from ".$existing->owning_lib." to $owner");
2397 return $e->die_event unless
2398 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2400 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2402 $existing->owning_lib($owner);
2403 return $e->die_event unless $e->update_actor_workstation($existing);
2409 "attempt to register an existing workstation. returning existing ID");
2412 return $existing->id;
2415 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2419 my $ws = Fieldmapper::actor::workstation->new;
2420 $ws->owning_lib($owner);
2422 $e->create_actor_workstation($ws) or return $e->die_event;
2424 return $ws->id; # note: editor sets the id on the new object for us
2427 __PACKAGE__->register_method (
2428 method => 'workstation_list',
2429 api_name => 'open-ils.actor.workstation.list',
2431 Returns a list of workstations registered at the given location
2432 @param authtoken The login session key
2433 @param ids A list of org_unit.id's for the workstation owners
2436 sub workstation_list {
2437 my( $self, $conn, $authtoken, @orgs ) = @_;
2439 my $e = new_editor(authtoken=>$authtoken);
2440 return $e->event unless $e->checkauth;
2445 unless $e->allowed('REGISTER_WORKSTATION', $o);
2446 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2457 __PACKAGE__->register_method (
2458 method => 'fetch_patron_note',
2459 api_name => 'open-ils.actor.note.retrieve.all',
2462 Returns a list of notes for a given user
2463 Requestor must have VIEW_USER permission if pub==false and
2464 @param authtoken The login session key
2465 @param args Hash of params including
2466 patronid : the patron's id
2467 pub : true if retrieving only public notes
2471 sub fetch_patron_note {
2472 my( $self, $conn, $authtoken, $args ) = @_;
2473 my $patronid = $$args{patronid};
2475 my($reqr, $evt) = $U->checkses($authtoken);
2476 return $evt if $evt;
2479 ($patron, $evt) = $U->fetch_user($patronid);
2480 return $evt if $evt;
2483 if( $patronid ne $reqr->id ) {
2484 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2485 return $evt if $evt;
2487 return $U->cstorereq(
2488 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2489 { usr => $patronid, pub => 't' } );
2492 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2493 return $evt if $evt;
2495 return $U->cstorereq(
2496 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2499 __PACKAGE__->register_method (
2500 method => 'create_user_note',
2501 api_name => 'open-ils.actor.note.create',
2503 Creates a new note for the given user
2504 @param authtoken The login session key
2505 @param note The note object
2508 sub create_user_note {
2509 my( $self, $conn, $authtoken, $note ) = @_;
2510 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2511 return $e->die_event unless $e->checkauth;
2513 my $user = $e->retrieve_actor_user($note->usr)
2514 or return $e->die_event;
2516 return $e->die_event unless
2517 $e->allowed('UPDATE_USER',$user->home_ou);
2519 $note->creator($e->requestor->id);
2520 $e->create_actor_usr_note($note) or return $e->die_event;
2526 __PACKAGE__->register_method (
2527 method => 'delete_user_note',
2528 api_name => 'open-ils.actor.note.delete',
2530 Deletes a note for the given user
2531 @param authtoken The login session key
2532 @param noteid The note id
2535 sub delete_user_note {
2536 my( $self, $conn, $authtoken, $noteid ) = @_;
2538 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2539 return $e->die_event unless $e->checkauth;
2540 my $note = $e->retrieve_actor_usr_note($noteid)
2541 or return $e->die_event;
2542 my $user = $e->retrieve_actor_user($note->usr)
2543 or return $e->die_event;
2544 return $e->die_event unless
2545 $e->allowed('UPDATE_USER', $user->home_ou);
2547 $e->delete_actor_usr_note($note) or return $e->die_event;
2553 __PACKAGE__->register_method (
2554 method => 'update_user_note',
2555 api_name => 'open-ils.actor.note.update',
2557 @param authtoken The login session key
2558 @param note The note
2562 sub update_user_note {
2563 my( $self, $conn, $auth, $note ) = @_;
2564 my $e = new_editor(authtoken=>$auth, xact=>1);
2565 return $e->event unless $e->checkauth;
2566 my $patron = $e->retrieve_actor_user($note->usr)
2567 or return $e->event;
2568 return $e->event unless
2569 $e->allowed('UPDATE_USER', $patron->home_ou);
2570 $e->update_actor_user_note($note)
2571 or return $e->event;
2579 __PACKAGE__->register_method (
2580 method => 'create_closed_date',
2581 api_name => 'open-ils.actor.org_unit.closed_date.create',
2583 Creates a new closing entry for the given org_unit
2584 @param authtoken The login session key
2585 @param note The closed_date object
2588 sub create_closed_date {
2589 my( $self, $conn, $authtoken, $cd ) = @_;
2591 my( $user, $evt ) = $U->checkses($authtoken);
2592 return $evt if $evt;
2594 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2595 return $evt if $evt;
2597 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2599 my $id = $U->storagereq(
2600 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2601 return $U->DB_UPDATE_FAILED($cd) unless $id;
2606 __PACKAGE__->register_method (
2607 method => 'delete_closed_date',
2608 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2610 Deletes a closing entry for the given org_unit
2611 @param authtoken The login session key
2612 @param noteid The close_date id
2615 sub delete_closed_date {
2616 my( $self, $conn, $authtoken, $cd ) = @_;
2618 my( $user, $evt ) = $U->checkses($authtoken);
2619 return $evt if $evt;
2622 ($cd_obj, $evt) = fetch_closed_date($cd);
2623 return $evt if $evt;
2625 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2626 return $evt if $evt;
2628 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2630 my $stat = $U->storagereq(
2631 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2632 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2637 __PACKAGE__->register_method(
2638 method => 'usrname_exists',
2639 api_name => 'open-ils.actor.username.exists',
2641 Returns 1 if the requested username exists, returns 0 otherwise
2645 sub usrname_exists {
2646 my( $self, $conn, $auth, $usrname ) = @_;
2647 my $e = new_editor(authtoken=>$auth);
2648 return $e->event unless $e->checkauth;
2649 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2650 return $$a[0] if $a and @$a;
2654 __PACKAGE__->register_method(
2655 method => 'barcode_exists',
2656 api_name => 'open-ils.actor.barcode.exists',
2659 Returns 1 if the requested barcode exists, returns 0 otherwise
2663 sub barcode_exists {
2664 my( $self, $conn, $auth, $barcode ) = @_;
2665 my $e = new_editor(authtoken=>$auth);
2666 return $e->event unless $e->checkauth;
2667 my $card = $e->search_actor_card({barcode => $barcode});
2668 return undef unless @$card;
2669 return $card->[0]->usr;
2673 __PACKAGE__->register_method(
2674 method => 'retrieve_net_levels',
2675 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2678 sub retrieve_net_levels {
2679 my( $self, $conn, $auth ) = @_;
2680 my $e = new_editor(authtoken=>$auth);
2681 return $e->event unless $e->checkauth;
2682 return $e->retrieve_all_config_net_access_level();
2686 __PACKAGE__->register_method(
2687 method => 'fetch_org_by_shortname',
2688 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2690 sub fetch_org_by_shortname {
2691 my( $self, $conn, $sname ) = @_;
2692 my $e = new_editor();
2693 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2694 return $e->event unless $org;
2699 __PACKAGE__->register_method(
2700 method => 'session_home_lib',
2701 api_name => 'open-ils.actor.session.home_lib',
2704 sub session_home_lib {
2705 my( $self, $conn, $auth ) = @_;
2706 my $e = new_editor(authtoken=>$auth);
2707 return undef unless $e->checkauth;
2708 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2709 return $org->shortname;
2712 __PACKAGE__->register_method(
2713 method => 'session_safe_token',
2714 api_name => 'open-ils.actor.session.safe_token',
2716 Returns a hashed session ID that is safe for export to the world.
2717 This safe token will expire after 1 hour of non-use.
2718 @param auth Active authentication token
2722 sub session_safe_token {
2723 my( $self, $conn, $auth ) = @_;
2724 my $e = new_editor(authtoken=>$auth);
2725 return undef unless $e->checkauth;
2727 my $safe_token = md5_hex($auth);
2729 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2731 # Add more like the following if needed...
2733 "safe-token-home_lib-shortname-$safe_token",
2734 $e->retrieve_actor_org_unit(
2735 $e->requestor->home_ou
2744 __PACKAGE__->register_method(
2745 method => 'safe_token_home_lib',
2746 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2748 Returns the home library shortname from the session
2749 asscociated with a safe token from generated by
2750 open-ils.actor.session.safe_token.
2751 @param safe_token Active safe token
2755 sub safe_token_home_lib {
2756 my( $self, $conn, $safe_token ) = @_;
2758 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2759 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2764 __PACKAGE__->register_method(
2765 method => 'slim_tree',
2766 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2769 my $tree = new_editor()->search_actor_org_unit(
2771 {"parent_ou" => undef },
2774 flesh_fields => { aou => ['children'] },
2775 order_by => { aou => 'name'},
2776 select => { aou => ["id","shortname", "name"]},
2781 return trim_tree($tree);
2787 return undef unless $tree;
2789 code => $tree->shortname,
2790 name => $tree->name,
2792 if( $tree->children and @{$tree->children} ) {
2793 $htree->{children} = [];
2794 for my $c (@{$tree->children}) {
2795 push( @{$htree->{children}}, trim_tree($c) );
2803 __PACKAGE__->register_method(
2804 method => "update_penalties",
2805 api_name => "open-ils.actor.user.penalties.update");
2806 sub update_penalties {
2807 my( $self, $conn, $auth, $userid ) = @_;
2808 my $e = new_editor(authtoken=>$auth);
2809 return $e->event unless $e->checkauth;
2810 $U->update_patron_penalties(
2812 patronid => $userid,
2819 __PACKAGE__->register_method(
2820 method => "user_retrieve_fleshed_by_id",
2821 api_name => "open-ils.actor.user.fleshed.retrieve",);
2823 sub user_retrieve_fleshed_by_id {
2824 my( $self, $client, $auth, $user_id, $fields ) = @_;
2825 my $e = new_editor(authtoken => $auth);
2826 return $e->event unless $e->checkauth;
2828 if( $e->requestor->id != $user_id ) {
2829 return $e->event unless $e->allowed('VIEW_USER');
2835 "standing_penalties",
2839 "stat_cat_entries" ];
2840 return new_flesh_user($user_id, $fields, $e);
2844 sub new_flesh_user {
2847 my $fields = shift || [];
2848 my $e = shift || new_editor(xact=>1);
2850 my $user = $e->retrieve_actor_user(
2855 "flesh_fields" => { "au" => $fields }
2858 ) or return $e->event;
2861 if( grep { $_ eq 'addresses' } @$fields ) {
2863 $user->addresses([]) unless @{$user->addresses};
2865 if( ref $user->billing_address ) {
2866 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2867 push( @{$user->addresses}, $user->billing_address );
2871 if( ref $user->mailing_address ) {
2872 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2873 push( @{$user->addresses}, $user->mailing_address );
2879 $user->clear_passwd();
2886 __PACKAGE__->register_method(
2887 method => "user_retrieve_parts",
2888 api_name => "open-ils.actor.user.retrieve.parts",);
2890 sub user_retrieve_parts {
2891 my( $self, $client, $auth, $user_id, $fields ) = @_;
2892 my $e = new_editor(authtoken => $auth);
2893 return $e->event unless $e->checkauth;
2894 if( $e->requestor->id != $user_id ) {
2895 return $e->event unless $e->allowed('VIEW_USER');
2898 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2899 push(@resp, $user->$_()) for(@$fields);
2905 __PACKAGE__->register_method(
2906 method => 'user_opt_in_enabled',
2907 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2909 @return 1 if user opt-in is globally enabled, 0 otherwise.
2912 sub user_opt_in_enabled {
2913 my($self, $conn) = @_;
2914 my $sc = OpenSRF::Utils::SettingsClient->new;
2915 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2920 __PACKAGE__->register_method(
2921 method => 'user_opt_in_at_org',
2922 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2924 @param $auth The auth token
2925 @param user_id The ID of the user to test
2926 @return 1 if the user has opted in at the specified org,
2927 event on error, and 0 otherwise. /);
2928 sub user_opt_in_at_org {
2929 my($self, $conn, $auth, $user_id) = @_;
2931 # see if we even need to enforce the opt-in value
2932 return 1 unless user_opt_in_enabled($self);
2934 my $e = new_editor(authtoken => $auth);
2935 return $e->event unless $e->checkauth;
2936 my $org_id = $e->requestor->ws_ou;
2938 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2939 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2941 # user is automatically opted-in at the home org
2942 return 1 if $user->home_ou eq $org_id;
2944 my $vals = $e->search_actor_usr_org_unit_opt_in(
2945 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2951 __PACKAGE__->register_method(
2952 method => 'create_user_opt_in_at_org',
2953 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2955 @param $auth The auth token
2956 @param user_id The ID of the user to test
2957 @return The ID of the newly created object, event on error./);
2959 sub create_user_opt_in_at_org {
2960 my($self, $conn, $auth, $user_id) = @_;
2962 my $e = new_editor(authtoken => $auth, xact=>1);
2963 return $e->die_event unless $e->checkauth;
2964 my $org_id = $e->requestor->ws_ou;
2966 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2967 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2969 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2971 $opt_in->org_unit($org_id);
2972 $opt_in->usr($user_id);
2973 $opt_in->staff($e->requestor->id);
2974 $opt_in->opt_in_ts('now');
2975 $opt_in->opt_in_ws($e->requestor->wsid);
2977 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2978 or return $e->die_event;