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 __PACKAGE__->register_method(
1316 method => 'check_user_work_perms',
1317 api_name => 'open-ils.actor.user.work_perm.highest_org_tree_set',
1320 @see open-ils.actor.user.work_perm.highest_org_set
1321 Returns a list of org trees. The root of each tree
1322 is the highest org in the organization hierarchy where the user has the
1323 requested permission. Below each tree root is its full tree of descendants.
1327 sub check_user_work_perms {
1328 my($self, $conn, $auth, $perm, $options) = @_;
1329 my $e = new_editor(authtoken=>$auth);
1330 return $e->event unless $e->checkauth;
1331 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1332 return $orglist unless $self->api_name =~ /tree/;
1333 return get_org_descendants($self, $conn, $orglist);
1337 __PACKAGE__->register_method(
1338 method => 'check_user_perms4',
1339 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1341 Returns the highest org unit id at which a user has a given permission
1342 If the requestor does not match the target user, the requestor must have
1343 'VIEW_PERMISSION' rights at the home org unit of the target user
1344 @param authtoken The login session key
1345 @param userid The id of the user in question
1346 @param perms An array of perm names to check
1347 @return An array of orgId's representing the org unit
1348 highest in the org tree within which the user has the requested permission
1349 The arrah of orgId's has matches the order of the perms array
1352 sub check_user_perms4 {
1353 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1355 my( $staff, $target, $org, $evt );
1357 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1358 $authtoken, $userid, 'VIEW_PERMISSION' );
1359 return $evt if $evt;
1362 return [] unless ref($perms);
1363 my $tree = $U->get_org_tree();
1365 for my $p (@$perms) {
1366 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1374 __PACKAGE__->register_method(
1375 method => "user_fines_summary",
1376 api_name => "open-ils.actor.user.fines.summary",
1378 notes => <<" NOTES");
1379 Returns a short summary of the users total open fines, excluding voided fines
1380 Params are login_session, user_id
1381 Returns a 'mous' object.
1384 sub user_fines_summary {
1385 my( $self, $client, $auth, $user_id ) = @_;
1386 my $e = new_editor(authtoken=>$auth);
1387 return $e->event unless $e->checkauth;
1388 my $user = $e->retrieve_actor_user($user_id)
1389 or return $e->event;
1391 if( $user_id ne $e->requestor->id ) {
1392 return $e->event unless
1393 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1396 # run this inside a transaction to prevent replication delay errors
1397 my $ses = $U->start_db_session();
1398 my $s = $ses->request(
1399 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1400 $U->rollback_db_session($ses);
1407 __PACKAGE__->register_method(
1408 method => "user_transactions",
1409 api_name => "open-ils.actor.user.transactions",
1410 notes => <<" NOTES");
1411 Returns a list of open user transactions (mbts objects);
1412 Params are login_session, user_id
1413 Optional third parameter is the transactions type. defaults to all
1416 __PACKAGE__->register_method(
1417 method => "user_transactions",
1418 api_name => "open-ils.actor.user.transactions.have_charge",
1419 notes => <<" NOTES");
1420 Returns a list of all open user transactions (mbts objects) that have an initial charge
1421 Params are login_session, user_id
1422 Optional third parameter is the transactions type. defaults to all
1425 __PACKAGE__->register_method(
1426 method => "user_transactions",
1427 api_name => "open-ils.actor.user.transactions.have_balance",
1428 notes => <<" NOTES");
1429 Returns a list of all open user transactions (mbts objects) that have a balance
1430 Params are login_session, user_id
1431 Optional third parameter is the transactions type. defaults to all
1434 __PACKAGE__->register_method(
1435 method => "user_transactions",
1436 api_name => "open-ils.actor.user.transactions.fleshed",
1437 notes => <<" NOTES");
1438 Returns an object/hash of transaction, circ, title where transaction = an open
1439 user transactions (mbts objects), circ is the attached circluation, and title
1440 is the title the circ points to
1441 Params are login_session, user_id
1442 Optional third parameter is the transactions type. defaults to all
1445 __PACKAGE__->register_method(
1446 method => "user_transactions",
1447 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1448 notes => <<" NOTES");
1449 Returns an object/hash of transaction, circ, title where transaction = an open
1450 user transactions that has an initial charge (mbts objects), circ is the
1451 attached circluation, and title is the title the circ points to
1452 Params are login_session, user_id
1453 Optional third parameter is the transactions type. defaults to all
1456 __PACKAGE__->register_method(
1457 method => "user_transactions",
1458 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1459 notes => <<" NOTES");
1460 Returns an object/hash of transaction, circ, title where transaction = an open
1461 user transaction that has a balance (mbts objects), circ is the attached
1462 circluation, and title is the title the circ points to
1463 Params are login_session, user_id
1464 Optional third parameter is the transaction type. defaults to all
1467 __PACKAGE__->register_method(
1468 method => "user_transactions",
1469 api_name => "open-ils.actor.user.transactions.count",
1470 notes => <<" NOTES");
1471 Returns an object/hash of transaction, circ, title where transaction = an open
1472 user transactions (mbts objects), circ is the attached circluation, and title
1473 is the title the circ points to
1474 Params are login_session, user_id
1475 Optional third parameter is the transactions type. defaults to all
1478 __PACKAGE__->register_method(
1479 method => "user_transactions",
1480 api_name => "open-ils.actor.user.transactions.have_charge.count",
1481 notes => <<" NOTES");
1482 Returns an object/hash of transaction, circ, title where transaction = an open
1483 user transactions that has an initial charge (mbts objects), circ is the
1484 attached circluation, and title is the title the circ points to
1485 Params are login_session, user_id
1486 Optional third parameter is the transactions type. defaults to all
1489 __PACKAGE__->register_method(
1490 method => "user_transactions",
1491 api_name => "open-ils.actor.user.transactions.have_balance.count",
1492 notes => <<" NOTES");
1493 Returns an object/hash of transaction, circ, title where transaction = an open
1494 user transaction that has a balance (mbts objects), circ is the attached
1495 circluation, and title is the title the circ points to
1496 Params are login_session, user_id
1497 Optional third parameter is the transaction type. defaults to all
1500 __PACKAGE__->register_method(
1501 method => "user_transactions",
1502 api_name => "open-ils.actor.user.transactions.have_balance.total",
1503 notes => <<" NOTES");
1504 Returns an object/hash of transaction, circ, title where transaction = an open
1505 user transaction that has a balance (mbts objects), circ is the attached
1506 circluation, and title is the title the circ points to
1507 Params are login_session, user_id
1508 Optional third parameter is the transaction type. defaults to all
1513 sub user_transactions {
1514 my( $self, $client, $login_session, $user_id, $type ) = @_;
1516 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1517 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1518 return $evt if $evt;
1520 my $api = $self->api_name();
1524 if(defined($type)) { @xact = (xact_type => $type);
1526 } else { @xact = (); }
1529 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1530 ->run($login_session => $user_id => $type);
1532 if($api =~ /have_charge/o) {
1534 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1536 } elsif($api =~ /have_balance/o) {
1538 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1541 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1545 if($api =~ /total/o) {
1547 for my $t (@$trans) {
1548 $total += $t->balance_owed;
1551 $logger->debug("Total balance owed by user $user_id: $total");
1555 if($api =~ /count/o) { return scalar @$trans; }
1556 if($api !~ /fleshed/o) { return $trans; }
1559 for my $t (@$trans) {
1561 if( $t->xact_type ne 'circulation' ) {
1562 push @resp, {transaction => $t};
1566 my $circ = $apputils->simple_scalar_request(
1568 "open-ils.cstore.direct.action.circulation.retrieve",
1573 my $title = $apputils->simple_scalar_request(
1575 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1576 $circ->target_copy );
1580 my $u = OpenILS::Utils::ModsParser->new();
1581 $u->start_mods_batch($title->marc());
1582 my $mods = $u->finish_mods_batch();
1583 $mods->doc_id($title->id) if $mods;
1585 push @resp, {transaction => $t, circ => $circ, record => $mods };
1593 __PACKAGE__->register_method(
1594 method => "user_transaction_retrieve",
1595 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1597 notes => <<" NOTES");
1598 Returns a fleshedtransaction record
1600 __PACKAGE__->register_method(
1601 method => "user_transaction_retrieve",
1602 api_name => "open-ils.actor.user.transaction.retrieve",
1604 notes => <<" NOTES");
1605 Returns a transaction record
1607 sub user_transaction_retrieve {
1608 my( $self, $client, $login_session, $bill_id ) = @_;
1610 # XXX I think I'm deprecated... make sure
1612 my $trans = $apputils->simple_scalar_request(
1614 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1618 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1619 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1620 return $evt if $evt;
1622 my $api = $self->api_name();
1623 if($api !~ /fleshed/o) { return $trans; }
1625 if( $trans->xact_type ne 'circulation' ) {
1626 $logger->debug("Returning non-circ transaction");
1627 return {transaction => $trans};
1630 my $circ = $apputils->simple_scalar_request(
1632 "open-ils..direct.action.circulation.retrieve",
1635 return {transaction => $trans} unless $circ;
1636 $logger->debug("Found the circ transaction");
1638 my $title = $apputils->simple_scalar_request(
1640 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1641 $circ->target_copy );
1643 return {transaction => $trans, circ => $circ } unless $title;
1644 $logger->debug("Found the circ title");
1648 my $u = OpenILS::Utils::ModsParser->new();
1649 $u->start_mods_batch($title->marc());
1650 $mods = $u->finish_mods_batch();
1652 if ($title->id == OILS_PRECAT_RECORD) {
1653 my $copy = $apputils->simple_scalar_request(
1655 "open-ils.cstore.direct.asset.copy.retrieve",
1656 $circ->target_copy );
1658 $mods = new Fieldmapper::metabib::virtual_record;
1659 $mods->doc_id(OILS_PRECAT_RECORD);
1660 $mods->title($copy->dummy_title);
1661 $mods->author($copy->dummy_author);
1665 $logger->debug("MODSized the circ title");
1667 return {transaction => $trans, circ => $circ, record => $mods };
1671 __PACKAGE__->register_method(
1672 method => "hold_request_count",
1673 api_name => "open-ils.actor.user.hold_requests.count",
1676 notes => <<" NOTES");
1677 Returns hold ready/total counts
1679 sub hold_request_count {
1680 my( $self, $client, $login_session, $userid ) = @_;
1682 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1683 $login_session, $userid, 'VIEW_HOLD' );
1684 return $evt if $evt;
1687 my $holds = $apputils->simple_scalar_request(
1689 "open-ils.cstore.direct.action.hold_request.search.atomic",
1692 fulfillment_time => {"=" => undef },
1693 cancel_time => undef,
1698 for my $h (@$holds) {
1699 next unless $h->capture_time and $h->current_copy;
1701 my $copy = $apputils->simple_scalar_request(
1703 "open-ils.cstore.direct.asset.copy.retrieve",
1707 if ($copy and $copy->status == 8) {
1712 return { total => scalar(@$holds), ready => scalar(@ready) };
1716 __PACKAGE__->register_method(
1717 method => "checkedout_count",
1718 api_name => "open-ils.actor.user.checked_out.count__",
1720 notes => <<" NOTES");
1721 Returns a transaction record
1725 sub checkedout_count {
1726 my( $self, $client, $login_session, $userid ) = @_;
1728 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1729 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1730 return $evt if $evt;
1732 my $circs = $apputils->simple_scalar_request(
1734 "open-ils.cstore.direct.action.circulation.search.atomic",
1735 { usr => $userid, stop_fines => undef }
1736 #{ usr => $userid, checkin_time => {"=" => undef } }
1739 my $parser = DateTime::Format::ISO8601->new;
1742 for my $c (@$circs) {
1743 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1744 my $due = $due_dt->epoch;
1746 if ($due < DateTime->today->epoch) {
1751 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1755 __PACKAGE__->register_method(
1756 method => "checked_out",
1757 api_name => "open-ils.actor.user.checked_out",
1761 Returns a structure of circulations objects sorted by
1762 out, overdue, lost, claims_returned, long_overdue.
1763 A list of IDs are returned of each type.
1764 lost, long_overdue, and claims_returned circ will not
1765 be "finished" (there is an outstanding balance or some
1766 other pending action on the circ).
1768 The .count method also includes a 'total' field which
1769 sums all "open" circs
1773 __PACKAGE__->register_method(
1774 method => "checked_out",
1775 api_name => "open-ils.actor.user.checked_out.count",
1778 signature => q/@see open-ils.actor.user.checked_out/
1782 my( $self, $conn, $auth, $userid ) = @_;
1784 my $e = new_editor(authtoken=>$auth);
1785 return $e->event unless $e->checkauth;
1787 if( $userid ne $e->requestor->id ) {
1788 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1791 my $count = $self->api_name =~ /count/;
1792 return _checked_out( $count, $e, $userid );
1796 my( $iscount, $e, $userid ) = @_;
1799 my $meth = 'open-ils.storage.actor.user.checked_out';
1800 $meth = "$meth.count" if $iscount;
1801 return $U->storagereq($meth, $userid);
1803 # XXX Old code - moved to storage
1804 #------------------------------------------------------------------------------
1805 #------------------------------------------------------------------------------
1806 my $circs = $e->search_action_circulation(
1807 { usr => $userid, checkin_time => undef });
1809 my $parser = DateTime::Format::ISO8601->new;
1811 # split the circs up into overdue and not-overdue circs
1813 for my $c (@$circs) {
1814 if( $c->due_date ) {
1815 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1816 my $due = $due_dt->epoch;
1817 if ($due < DateTime->today->epoch) {
1827 my( @open, @od, @lost, @cr, @lo );
1829 while (my $c = shift(@out)) {
1830 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1831 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1832 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1833 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1836 while (my $c = shift(@overdue)) {
1837 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1838 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1839 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1840 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1845 total => @open + @od + @lost + @cr + @lo,
1846 out => scalar(@open),
1847 overdue => scalar(@od),
1848 lost => scalar(@lost),
1849 claims_returned => scalar(@cr),
1850 long_overdue => scalar(@lo)
1858 claims_returned => \@cr,
1859 long_overdue => \@lo
1864 sub _checked_out_WHAT {
1865 my( $iscount, $e, $userid ) = @_;
1867 my $circs = $e->search_action_circulation(
1868 { usr => $userid, stop_fines => undef });
1870 my $mcircs = $e->search_action_circulation(
1873 checkin_time => undef,
1874 xact_finish => undef,
1878 push( @$circs, @$mcircs );
1880 my $parser = DateTime::Format::ISO8601->new;
1882 # split the circs up into overdue and not-overdue circs
1884 for my $c (@$circs) {
1885 if( $c->due_date ) {
1886 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1887 my $due = $due_dt->epoch;
1888 if ($due < DateTime->today->epoch) {
1889 push @overdue, $c->id;
1898 # grab all of the lost, claims-returned, and longoverdue circs
1899 #my $open = $e->search_action_circulation(
1900 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1903 # these items have stop_fines, but no xact_finish, so money
1904 # is owed on them and they have not been checked in
1905 my $open = $e->search_action_circulation(
1908 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1909 xact_finish => undef,
1910 checkin_time => undef,
1915 my( @lost, @cr, @lo );
1916 for my $c (@$open) {
1917 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1918 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1919 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1925 total => @$circs + @lost + @cr + @lo,
1926 out => scalar(@out),
1927 overdue => scalar(@overdue),
1928 lost => scalar(@lost),
1929 claims_returned => scalar(@cr),
1930 long_overdue => scalar(@lo)
1936 overdue => \@overdue,
1938 claims_returned => \@cr,
1939 long_overdue => \@lo
1945 __PACKAGE__->register_method(
1946 method => "checked_in_with_fines",
1947 api_name => "open-ils.actor.user.checked_in_with_fines",
1950 signature => q/@see open-ils.actor.user.checked_out/
1952 sub checked_in_with_fines {
1953 my( $self, $conn, $auth, $userid ) = @_;
1955 my $e = new_editor(authtoken=>$auth);
1956 return $e->event unless $e->checkauth;
1958 if( $userid ne $e->requestor->id ) {
1959 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1962 # money is owed on these items and they are checked in
1963 my $open = $e->search_action_circulation(
1966 xact_finish => undef,
1967 checkin_time => { "!=" => undef },
1972 my( @lost, @cr, @lo );
1973 for my $c (@$open) {
1974 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1975 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1976 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1981 claims_returned => \@cr,
1982 long_overdue => \@lo
1994 __PACKAGE__->register_method(
1995 method => "user_transaction_history",
1996 api_name => "open-ils.actor.user.transactions.history",
1998 notes => <<" NOTES");
1999 Returns a list of billable transaction ids for a user, optionally by type
2001 __PACKAGE__->register_method(
2002 method => "user_transaction_history",
2003 api_name => "open-ils.actor.user.transactions.history.have_charge",
2005 notes => <<" NOTES");
2006 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2008 __PACKAGE__->register_method(
2009 method => "user_transaction_history",
2010 api_name => "open-ils.actor.user.transactions.history.have_balance",
2013 notes => <<" NOTES");
2014 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2016 __PACKAGE__->register_method(
2017 method => "user_transaction_history",
2018 api_name => "open-ils.actor.user.transactions.history.still_open",
2020 notes => <<" NOTES");
2021 Returns a list of billable transaction ids for a user that are not finished
2023 __PACKAGE__->register_method(
2024 method => "user_transaction_history",
2025 api_name => "open-ils.actor.user.transactions.history.have_bill",
2028 notes => <<" NOTES");
2029 Returns a list of billable transaction ids for a user that has billings
2035 sub _user_transaction_history {
2036 my( $self, $client, $login_session, $user_id, $type ) = @_;
2038 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2039 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2040 return $evt if $evt;
2042 my $api = $self->api_name();
2047 @xact = (xact_type => $type) if(defined($type));
2048 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2049 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2051 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2053 my $trans = $apputils->simple_scalar_request(
2055 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2056 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2058 return [ map { $_->id } @$trans ];
2062 =head SEE APPUTILS.PM
2067 for my $x (@xacts) {
2068 my $s = new Fieldmapper::money::billable_transaction_summary;
2071 $s->xact_start( $x->xact_start );
2072 $s->xact_finish( $x->xact_finish );
2076 for my $b (@{ $x->billings }) {
2077 next if ($U->is_true($b->voided));
2078 $to += ($b->amount * 100);
2079 $lb ||= $b->billing_ts;
2080 if ($b->billing_ts ge $lb) {
2081 $lb = $b->billing_ts;
2082 $s->last_billing_note($b->note);
2083 $s->last_billing_ts($b->billing_ts);
2084 $s->last_billing_type($b->billing_type);
2088 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2092 for my $p (@{ $x->payments }) {
2093 next if ($U->is_true($p->voided));
2094 $tp += ($p->amount * 100);
2095 $lp ||= $p->payment_ts;
2096 if ($p->payment_ts ge $lp) {
2097 $lp = $p->payment_ts;
2098 $s->last_payment_note($p->note);
2099 $s->last_payment_ts($p->payment_ts);
2100 $s->last_payment_type($p->payment_type);
2103 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2105 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2107 $s->xact_type( 'grocery' ) if ($x->grocery);
2108 $s->xact_type( 'circulation' ) if ($x->circulation);
2117 sub user_transaction_history {
2118 my( $self, $conn, $auth, $userid, $type ) = @_;
2120 # run inside of a transaction to prevent replication delays
2121 my $e = new_editor(xact=>1, authtoken=>$auth);
2122 return $e->die_event unless $e->checkauth;
2124 if( $e->requestor->id ne $userid ) {
2125 return $e->die_event
2126 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2129 my $api = $self->api_name;
2130 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2132 my @xacts = @{ $e->search_money_billable_transaction(
2133 [ { usr => $userid, @xact_finish },
2135 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2136 order_by => { mbt => 'xact_start DESC' },
2144 #my @mbts = _make_mbts( @xacts );
2145 my @mbts = $U->make_mbts( @xacts );
2147 if(defined($type)) {
2148 @mbts = grep { $_->xact_type eq $type } @mbts;
2151 if($api =~ /have_balance/o) {
2152 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2155 if($api =~ /have_charge/o) {
2156 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2159 if($api =~ /have_bill/o) {
2160 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2168 __PACKAGE__->register_method(
2169 method => "user_perms",
2170 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2172 notes => <<" NOTES");
2173 Returns a list of permissions
2176 my( $self, $client, $authtoken, $user ) = @_;
2178 my( $staff, $evt ) = $apputils->checkses($authtoken);
2179 return $evt if $evt;
2181 $user ||= $staff->id;
2183 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2187 return $apputils->simple_scalar_request(
2189 "open-ils.storage.permission.user_perms.atomic",
2193 __PACKAGE__->register_method(
2194 method => "retrieve_perms",
2195 api_name => "open-ils.actor.permissions.retrieve",
2196 notes => <<" NOTES");
2197 Returns a list of permissions
2199 sub retrieve_perms {
2200 my( $self, $client ) = @_;
2201 return $apputils->simple_scalar_request(
2203 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2204 { id => { '!=' => undef } }
2208 __PACKAGE__->register_method(
2209 method => "retrieve_groups",
2210 api_name => "open-ils.actor.groups.retrieve",
2211 notes => <<" NOTES");
2212 Returns a list of user groupss
2214 sub retrieve_groups {
2215 my( $self, $client ) = @_;
2216 return new_editor()->retrieve_all_permission_grp_tree();
2219 __PACKAGE__->register_method(
2220 method => "retrieve_org_address",
2221 api_name => "open-ils.actor.org_unit.address.retrieve",
2222 notes => <<' NOTES');
2223 Returns an org_unit address by ID
2224 @param An org_address ID
2226 sub retrieve_org_address {
2227 my( $self, $client, $id ) = @_;
2228 return $apputils->simple_scalar_request(
2230 "open-ils.cstore.direct.actor.org_address.retrieve",
2235 __PACKAGE__->register_method(
2236 method => "retrieve_groups_tree",
2237 api_name => "open-ils.actor.groups.tree.retrieve",
2238 notes => <<" NOTES");
2239 Returns a list of user groups
2241 sub retrieve_groups_tree {
2242 my( $self, $client ) = @_;
2243 return new_editor()->search_permission_grp_tree(
2248 flesh_fields => { pgt => ["children"] },
2249 order_by => { pgt => 'name'}
2256 # turns an org list into an org tree
2258 sub build_group_tree {
2260 my( $self, $grplist) = @_;
2262 return $grplist unless (
2263 ref($grplist) and @$grplist > 1 );
2265 my @list = sort { $a->name cmp $b->name } @$grplist;
2268 for my $grp (@list) {
2270 if ($grp and !defined($grp->parent)) {
2274 my ($parent) = grep { $_->id == $grp->parent} @list;
2276 $parent->children([]) unless defined($parent->children);
2277 push( @{$parent->children}, $grp );
2285 __PACKAGE__->register_method(
2286 method => "add_user_to_groups",
2287 api_name => "open-ils.actor.user.set_groups",
2288 notes => <<" NOTES");
2289 Adds a user to one or more permission groups
2292 sub add_user_to_groups {
2293 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2295 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2296 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2297 return $evt if $evt;
2299 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2300 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2301 return $evt if $evt;
2303 $apputils->simplereq(
2305 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2307 for my $group (@$groups) {
2308 my $link = Fieldmapper::permission::usr_grp_map->new;
2310 $link->usr($userid);
2312 my $id = $apputils->simplereq(
2314 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2320 __PACKAGE__->register_method(
2321 method => "get_user_perm_groups",
2322 api_name => "open-ils.actor.user.get_groups",
2323 notes => <<" NOTES");
2324 Retrieve a user's permission groups.
2328 sub get_user_perm_groups {
2329 my( $self, $client, $authtoken, $userid ) = @_;
2331 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2332 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2333 return $evt if $evt;
2335 return $apputils->simplereq(
2337 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2341 __PACKAGE__->register_method(
2342 method => "get_user_work_ous",
2343 api_name => "open-ils.actor.user.get_work_ous",
2344 notes => <<" NOTES");
2345 Retrieve a user's work org units.
2347 __PACKAGE__->register_method(
2348 method => "get_user_work_ous",
2349 api_name => "open-ils.actor.user.get_work_ous.ids",
2350 notes => <<" NOTES");
2351 Retrieve a user's work org units.
2355 sub get_user_work_ous {
2356 my( $self, $client, $auth, $userid ) = @_;
2357 my $e = new_editor(authtoken=>$auth);
2358 return $e->event unless $e->checkauth;
2359 $userid ||= $e->requestor->id;
2361 if($e->requestor->id != $userid) {
2362 my $user = $e->retrieve_actor_user($userid)
2363 or return $e->event;
2364 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2367 return $e->search_permission_usr_work_ou_map({usr => $userid})
2368 unless $self->api_name =~ /.ids$/;
2370 # client just wants a list of org IDs
2371 return $U->get_user_work_ou_ids($e, $userid);
2377 __PACKAGE__->register_method (
2378 method => 'register_workstation',
2379 api_name => 'open-ils.actor.workstation.register.override',
2380 signature => q/@see open-ils.actor.workstation.register/);
2382 __PACKAGE__->register_method (
2383 method => 'register_workstation',
2384 api_name => 'open-ils.actor.workstation.register',
2386 Registers a new workstion in the system
2387 @param authtoken The login session key
2388 @param name The name of the workstation id
2389 @param owner The org unit that owns this workstation
2390 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2391 if the name is already in use.
2394 sub register_workstation {
2395 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2397 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2398 return $e->die_event unless $e->checkauth;
2399 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2400 my $existing = $e->search_actor_workstation({name => $name})->[0];
2404 if( $self->api_name =~ /override/o ) {
2405 # workstation with the given name exists.
2407 if($owner ne $existing->owning_lib) {
2408 # if necessary, update the owning_lib of the workstation
2410 $logger->info("changing owning lib of workstation ".$existing->id.
2411 " from ".$existing->owning_lib." to $owner");
2412 return $e->die_event unless
2413 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2415 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2417 $existing->owning_lib($owner);
2418 return $e->die_event unless $e->update_actor_workstation($existing);
2424 "attempt to register an existing workstation. returning existing ID");
2427 return $existing->id;
2430 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2434 my $ws = Fieldmapper::actor::workstation->new;
2435 $ws->owning_lib($owner);
2437 $e->create_actor_workstation($ws) or return $e->die_event;
2439 return $ws->id; # note: editor sets the id on the new object for us
2442 __PACKAGE__->register_method (
2443 method => 'workstation_list',
2444 api_name => 'open-ils.actor.workstation.list',
2446 Returns a list of workstations registered at the given location
2447 @param authtoken The login session key
2448 @param ids A list of org_unit.id's for the workstation owners
2451 sub workstation_list {
2452 my( $self, $conn, $authtoken, @orgs ) = @_;
2454 my $e = new_editor(authtoken=>$authtoken);
2455 return $e->event unless $e->checkauth;
2460 unless $e->allowed('REGISTER_WORKSTATION', $o);
2461 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2472 __PACKAGE__->register_method (
2473 method => 'fetch_patron_note',
2474 api_name => 'open-ils.actor.note.retrieve.all',
2477 Returns a list of notes for a given user
2478 Requestor must have VIEW_USER permission if pub==false and
2479 @param authtoken The login session key
2480 @param args Hash of params including
2481 patronid : the patron's id
2482 pub : true if retrieving only public notes
2486 sub fetch_patron_note {
2487 my( $self, $conn, $authtoken, $args ) = @_;
2488 my $patronid = $$args{patronid};
2490 my($reqr, $evt) = $U->checkses($authtoken);
2491 return $evt if $evt;
2494 ($patron, $evt) = $U->fetch_user($patronid);
2495 return $evt if $evt;
2498 if( $patronid ne $reqr->id ) {
2499 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2500 return $evt if $evt;
2502 return $U->cstorereq(
2503 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2504 { usr => $patronid, pub => 't' } );
2507 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2508 return $evt if $evt;
2510 return $U->cstorereq(
2511 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2514 __PACKAGE__->register_method (
2515 method => 'create_user_note',
2516 api_name => 'open-ils.actor.note.create',
2518 Creates a new note for the given user
2519 @param authtoken The login session key
2520 @param note The note object
2523 sub create_user_note {
2524 my( $self, $conn, $authtoken, $note ) = @_;
2525 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2526 return $e->die_event unless $e->checkauth;
2528 my $user = $e->retrieve_actor_user($note->usr)
2529 or return $e->die_event;
2531 return $e->die_event unless
2532 $e->allowed('UPDATE_USER',$user->home_ou);
2534 $note->creator($e->requestor->id);
2535 $e->create_actor_usr_note($note) or return $e->die_event;
2541 __PACKAGE__->register_method (
2542 method => 'delete_user_note',
2543 api_name => 'open-ils.actor.note.delete',
2545 Deletes a note for the given user
2546 @param authtoken The login session key
2547 @param noteid The note id
2550 sub delete_user_note {
2551 my( $self, $conn, $authtoken, $noteid ) = @_;
2553 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2554 return $e->die_event unless $e->checkauth;
2555 my $note = $e->retrieve_actor_usr_note($noteid)
2556 or return $e->die_event;
2557 my $user = $e->retrieve_actor_user($note->usr)
2558 or return $e->die_event;
2559 return $e->die_event unless
2560 $e->allowed('UPDATE_USER', $user->home_ou);
2562 $e->delete_actor_usr_note($note) or return $e->die_event;
2568 __PACKAGE__->register_method (
2569 method => 'update_user_note',
2570 api_name => 'open-ils.actor.note.update',
2572 @param authtoken The login session key
2573 @param note The note
2577 sub update_user_note {
2578 my( $self, $conn, $auth, $note ) = @_;
2579 my $e = new_editor(authtoken=>$auth, xact=>1);
2580 return $e->event unless $e->checkauth;
2581 my $patron = $e->retrieve_actor_user($note->usr)
2582 or return $e->event;
2583 return $e->event unless
2584 $e->allowed('UPDATE_USER', $patron->home_ou);
2585 $e->update_actor_user_note($note)
2586 or return $e->event;
2594 __PACKAGE__->register_method (
2595 method => 'create_closed_date',
2596 api_name => 'open-ils.actor.org_unit.closed_date.create',
2598 Creates a new closing entry for the given org_unit
2599 @param authtoken The login session key
2600 @param note The closed_date object
2603 sub create_closed_date {
2604 my( $self, $conn, $authtoken, $cd ) = @_;
2606 my( $user, $evt ) = $U->checkses($authtoken);
2607 return $evt if $evt;
2609 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2610 return $evt if $evt;
2612 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2614 my $id = $U->storagereq(
2615 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2616 return $U->DB_UPDATE_FAILED($cd) unless $id;
2621 __PACKAGE__->register_method (
2622 method => 'delete_closed_date',
2623 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2625 Deletes a closing entry for the given org_unit
2626 @param authtoken The login session key
2627 @param noteid The close_date id
2630 sub delete_closed_date {
2631 my( $self, $conn, $authtoken, $cd ) = @_;
2633 my( $user, $evt ) = $U->checkses($authtoken);
2634 return $evt if $evt;
2637 ($cd_obj, $evt) = fetch_closed_date($cd);
2638 return $evt if $evt;
2640 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2641 return $evt if $evt;
2643 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2645 my $stat = $U->storagereq(
2646 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2647 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2652 __PACKAGE__->register_method(
2653 method => 'usrname_exists',
2654 api_name => 'open-ils.actor.username.exists',
2656 Returns 1 if the requested username exists, returns 0 otherwise
2660 sub usrname_exists {
2661 my( $self, $conn, $auth, $usrname ) = @_;
2662 my $e = new_editor(authtoken=>$auth);
2663 return $e->event unless $e->checkauth;
2664 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2665 return $$a[0] if $a and @$a;
2669 __PACKAGE__->register_method(
2670 method => 'barcode_exists',
2671 api_name => 'open-ils.actor.barcode.exists',
2674 Returns 1 if the requested barcode exists, returns 0 otherwise
2678 sub barcode_exists {
2679 my( $self, $conn, $auth, $barcode ) = @_;
2680 my $e = new_editor(authtoken=>$auth);
2681 return $e->event unless $e->checkauth;
2682 my $card = $e->search_actor_card({barcode => $barcode});
2683 return undef unless @$card;
2684 return $card->[0]->usr;
2688 __PACKAGE__->register_method(
2689 method => 'retrieve_net_levels',
2690 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2693 sub retrieve_net_levels {
2694 my( $self, $conn, $auth ) = @_;
2695 my $e = new_editor(authtoken=>$auth);
2696 return $e->event unless $e->checkauth;
2697 return $e->retrieve_all_config_net_access_level();
2701 __PACKAGE__->register_method(
2702 method => 'fetch_org_by_shortname',
2703 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2705 sub fetch_org_by_shortname {
2706 my( $self, $conn, $sname ) = @_;
2707 my $e = new_editor();
2708 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2709 return $e->event unless $org;
2714 __PACKAGE__->register_method(
2715 method => 'session_home_lib',
2716 api_name => 'open-ils.actor.session.home_lib',
2719 sub session_home_lib {
2720 my( $self, $conn, $auth ) = @_;
2721 my $e = new_editor(authtoken=>$auth);
2722 return undef unless $e->checkauth;
2723 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2724 return $org->shortname;
2727 __PACKAGE__->register_method(
2728 method => 'session_safe_token',
2729 api_name => 'open-ils.actor.session.safe_token',
2731 Returns a hashed session ID that is safe for export to the world.
2732 This safe token will expire after 1 hour of non-use.
2733 @param auth Active authentication token
2737 sub session_safe_token {
2738 my( $self, $conn, $auth ) = @_;
2739 my $e = new_editor(authtoken=>$auth);
2740 return undef unless $e->checkauth;
2742 my $safe_token = md5_hex($auth);
2744 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2746 # Add more like the following if needed...
2748 "safe-token-home_lib-shortname-$safe_token",
2749 $e->retrieve_actor_org_unit(
2750 $e->requestor->home_ou
2759 __PACKAGE__->register_method(
2760 method => 'safe_token_home_lib',
2761 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2763 Returns the home library shortname from the session
2764 asscociated with a safe token from generated by
2765 open-ils.actor.session.safe_token.
2766 @param safe_token Active safe token
2770 sub safe_token_home_lib {
2771 my( $self, $conn, $safe_token ) = @_;
2773 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2774 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2779 __PACKAGE__->register_method(
2780 method => 'slim_tree',
2781 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2784 my $tree = new_editor()->search_actor_org_unit(
2786 {"parent_ou" => undef },
2789 flesh_fields => { aou => ['children'] },
2790 order_by => { aou => 'name'},
2791 select => { aou => ["id","shortname", "name"]},
2796 return trim_tree($tree);
2802 return undef unless $tree;
2804 code => $tree->shortname,
2805 name => $tree->name,
2807 if( $tree->children and @{$tree->children} ) {
2808 $htree->{children} = [];
2809 for my $c (@{$tree->children}) {
2810 push( @{$htree->{children}}, trim_tree($c) );
2818 __PACKAGE__->register_method(
2819 method => "update_penalties",
2820 api_name => "open-ils.actor.user.penalties.update");
2821 sub update_penalties {
2822 my( $self, $conn, $auth, $userid ) = @_;
2823 my $e = new_editor(authtoken=>$auth);
2824 return $e->event unless $e->checkauth;
2825 $U->update_patron_penalties(
2827 patronid => $userid,
2834 __PACKAGE__->register_method(
2835 method => "user_retrieve_fleshed_by_id",
2836 api_name => "open-ils.actor.user.fleshed.retrieve",);
2838 sub user_retrieve_fleshed_by_id {
2839 my( $self, $client, $auth, $user_id, $fields ) = @_;
2840 my $e = new_editor(authtoken => $auth);
2841 return $e->event unless $e->checkauth;
2843 if( $e->requestor->id != $user_id ) {
2844 return $e->event unless $e->allowed('VIEW_USER');
2850 "standing_penalties",
2854 "stat_cat_entries" ];
2855 return new_flesh_user($user_id, $fields, $e);
2859 sub new_flesh_user {
2862 my $fields = shift || [];
2863 my $e = shift || new_editor(xact=>1);
2865 my $user = $e->retrieve_actor_user(
2870 "flesh_fields" => { "au" => $fields }
2873 ) or return $e->event;
2876 if( grep { $_ eq 'addresses' } @$fields ) {
2878 $user->addresses([]) unless @{$user->addresses};
2880 if( ref $user->billing_address ) {
2881 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2882 push( @{$user->addresses}, $user->billing_address );
2886 if( ref $user->mailing_address ) {
2887 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2888 push( @{$user->addresses}, $user->mailing_address );
2894 $user->clear_passwd();
2901 __PACKAGE__->register_method(
2902 method => "user_retrieve_parts",
2903 api_name => "open-ils.actor.user.retrieve.parts",);
2905 sub user_retrieve_parts {
2906 my( $self, $client, $auth, $user_id, $fields ) = @_;
2907 my $e = new_editor(authtoken => $auth);
2908 return $e->event unless $e->checkauth;
2909 if( $e->requestor->id != $user_id ) {
2910 return $e->event unless $e->allowed('VIEW_USER');
2913 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2914 push(@resp, $user->$_()) for(@$fields);
2920 __PACKAGE__->register_method(
2921 method => 'user_opt_in_enabled',
2922 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2924 @return 1 if user opt-in is globally enabled, 0 otherwise.
2927 sub user_opt_in_enabled {
2928 my($self, $conn) = @_;
2929 my $sc = OpenSRF::Utils::SettingsClient->new;
2930 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2935 __PACKAGE__->register_method(
2936 method => 'user_opt_in_at_org',
2937 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2939 @param $auth The auth token
2940 @param user_id The ID of the user to test
2941 @return 1 if the user has opted in at the specified org,
2942 event on error, and 0 otherwise. /);
2943 sub user_opt_in_at_org {
2944 my($self, $conn, $auth, $user_id) = @_;
2946 # see if we even need to enforce the opt-in value
2947 return 1 unless user_opt_in_enabled($self);
2949 my $e = new_editor(authtoken => $auth);
2950 return $e->event unless $e->checkauth;
2951 my $org_id = $e->requestor->ws_ou;
2953 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2954 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2956 # user is automatically opted-in at the home org
2957 return 1 if $user->home_ou eq $org_id;
2959 my $vals = $e->search_actor_usr_org_unit_opt_in(
2960 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2966 __PACKAGE__->register_method(
2967 method => 'create_user_opt_in_at_org',
2968 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2970 @param $auth The auth token
2971 @param user_id The ID of the user to test
2972 @return The ID of the newly created object, event on error./);
2974 sub create_user_opt_in_at_org {
2975 my($self, $conn, $auth, $user_id) = @_;
2977 my $e = new_editor(authtoken => $auth, xact=>1);
2978 return $e->die_event unless $e->checkauth;
2979 my $org_id = $e->requestor->ws_ou;
2981 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2982 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2984 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2986 $opt_in->org_unit($org_id);
2987 $opt_in->usr($user_id);
2988 $opt_in->staff($e->requestor->id);
2989 $opt_in->opt_in_ts('now');
2990 $opt_in->opt_in_ws($e->requestor->wsid);
2992 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2993 or return $e->die_event;