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);
82 __PACKAGE__->register_method(
83 method => "set_ou_settings",
84 api_name => "open-ils.actor.org_unit.settings.update",
87 my( $self, $client, $user_session, $ouid, $settings ) = @_;
89 my( $staff, $evt ) = $apputils->checkses( $user_session );
91 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
95 for my $set (keys %$settings) {
97 my $json = OpenSRF::Utils::JSON->perl2JSON($$settings{$set});
98 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
101 { org_unit => $ouid, name => $set },
102 { value => $json } );
105 my $ses = $U->start_db_session();
106 my $stat = $ses->request(
107 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
108 $U->commit_db_session($ses);
114 my $fetch_user_settings;
115 my $fetch_ou_settings;
117 __PACKAGE__->register_method(
118 method => "user_settings",
119 api_name => "open-ils.actor.patron.settings.retrieve",
122 my( $self, $client, $user_session, $uid, $setting ) = @_;
124 my( $staff, $user, $evt ) =
125 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
128 $logger->debug("User " . $staff->id . " fetching user $uid\n");
129 my $s = $apputils->simplereq(
131 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
133 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
135 return $$settings{$setting} if $setting;
141 __PACKAGE__->register_method(
142 method => "ou_settings",
143 api_name => "open-ils.actor.org_unit.settings.retrieve",
146 my( $self, $client, $ouid ) = @_;
148 $logger->info("Fetching org unit settings for org $ouid");
150 my $s = $apputils->simplereq(
152 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
154 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
159 __PACKAGE__->register_method(
160 api_name => 'open-ils.actor.ou_setting.ancestor_default',
161 method => 'ou_ancestor_setting',
164 # ------------------------------------------------------------------
165 # Attempts to find the org setting value for a given org. if not
166 # found at the requested org, searches up the org tree until it
167 # finds a parent that has the requested setting.
168 # when found, returns { org => $id, value => $value }
169 # otherwise, returns NULL
170 # ------------------------------------------------------------------
171 sub ou_ancestor_setting {
172 my( $self, $client, $orgid, $name ) = @_;
173 return $U->ou_ancestor_setting($orgid, $name);
179 __PACKAGE__->register_method (
180 method => "ou_setting_delete",
181 api_name => 'open-ils.actor.org_setting.delete',
183 Deletes a specific org unit setting for a specific location
184 @param authtoken The login session key
185 @param orgid The org unit whose setting we're changing
186 @param setting The name of the setting to delete
187 @return True value on success.
191 sub ou_setting_delete {
192 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
193 my( $reqr, $evt) = $U->checkses($authtoken);
195 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
198 my $id = $U->cstorereq(
199 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
200 { name => $setting, org_unit => $orgid } );
202 $logger->debug("Retrieved setting $id in org unit setting delete");
204 my $s = $U->cstorereq(
205 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
207 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
221 __PACKAGE__->register_method(
222 method => "update_patron",
223 api_name => "open-ils.actor.patron.update",);
226 my( $self, $client, $user_session, $patron ) = @_;
228 my $session = $apputils->start_db_session();
232 $logger->info("Creating new patron...") if $patron->isnew;
233 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
235 my( $user_obj, $evt ) = $U->checkses($user_session);
238 $evt = check_group_perm($session, $user_obj, $patron);
242 # $new_patron is the patron in progress. $patron is the original patron
243 # passed in with the method. new_patron will change as the components
244 # of patron are added/updated.
248 # unflesh the real items on the patron
249 $patron->card( $patron->card->id ) if(ref($patron->card));
250 $patron->billing_address( $patron->billing_address->id )
251 if(ref($patron->billing_address));
252 $patron->mailing_address( $patron->mailing_address->id )
253 if(ref($patron->mailing_address));
255 # create/update the patron first so we can use his id
256 if($patron->isnew()) {
257 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
259 } else { $new_patron = $patron; }
261 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
264 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
267 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
270 # re-update the patron if anything has happened to him during this process
271 if($new_patron->ischanged()) {
272 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
276 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
279 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
282 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
285 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
288 if(!$patron->isnew) {
289 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
292 $apputils->commit_db_session($session);
293 my $fuser = flesh_user($new_patron->id());
296 # Log the new and old patron for investigation
297 $logger->info("$user_session updating patron object. orig patron object = ".
298 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
308 return new_flesh_user($id, [
311 "standing_penalties",
315 "stat_cat_entries" ] );
323 # clone and clear stuff that would break the database
327 my $new_patron = $patron->clone;
329 $new_patron->clear_billing_address();
330 $new_patron->clear_mailing_address();
331 $new_patron->clear_addresses();
332 $new_patron->clear_card();
333 $new_patron->clear_cards();
334 $new_patron->clear_id();
335 $new_patron->clear_isnew();
336 $new_patron->clear_ischanged();
337 $new_patron->clear_isdeleted();
338 $new_patron->clear_stat_cat_entries();
339 $new_patron->clear_permissions();
340 $new_patron->clear_standing_penalties();
350 my $user_obj = shift;
352 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
353 return (undef, $evt) if $evt;
355 my $ex = $session->request(
356 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
358 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
361 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
363 my $id = $session->request(
364 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
365 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
367 $logger->info("Successfully created new user [$id] in DB");
369 return ( $session->request(
370 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
374 sub check_group_perm {
375 my( $session, $requestor, $patron ) = @_;
378 # first let's see if the requestor has
379 # priveleges to update this user in any way
380 if( ! $patron->isnew ) {
381 my $p = $session->request(
382 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
384 # If we are the requestor (trying to update our own account)
385 # and we are not trying to change our profile, we're good
386 if( $p->id == $requestor->id and
387 $p->profile == $patron->profile ) {
392 $evt = group_perm_failed($session, $requestor, $p);
396 # They are allowed to edit this patron.. can they put the
397 # patron into the group requested?
398 $evt = group_perm_failed($session, $requestor, $patron);
404 sub group_perm_failed {
405 my( $session, $requestor, $patron ) = @_;
409 my $grpid = $patron->profile;
413 $logger->debug("user update looking for group perm for group $grpid");
414 $grp = $session->request(
415 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
416 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
418 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
420 $logger->info("user update checking perm $perm on user ".
421 $requestor->id." for update/create on user username=".$patron->usrname);
423 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
431 my( $session, $patron, $user_obj, $noperm) = @_;
433 $logger->info("Updating patron ".$patron->id." in DB");
438 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
439 return (undef, $evt) if $evt;
442 # update the password by itself to avoid the password protection magic
443 if( $patron->passwd ) {
444 my $s = $session->request(
445 'open-ils.storage.direct.actor.user.remote_update',
446 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
447 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
448 $patron->clear_passwd;
451 if(!$patron->ident_type) {
452 $patron->clear_ident_type;
453 $patron->clear_ident_value;
456 $evt = verify_last_xact($session, $patron);
457 return (undef, $evt) if $evt;
459 my $stat = $session->request(
460 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
461 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
466 sub verify_last_xact {
467 my( $session, $patron ) = @_;
468 return undef unless $patron->id and $patron->id > 0;
469 my $p = $session->request(
470 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
471 my $xact = $p->last_xact_id;
472 return undef unless $xact;
473 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
474 return OpenILS::Event->new('XACT_COLLISION')
475 if $xact != $patron->last_xact_id;
480 sub _check_dup_ident {
481 my( $session, $patron ) = @_;
483 return undef unless $patron->ident_value;
486 ident_type => $patron->ident_type,
487 ident_value => $patron->ident_value,
490 $logger->debug("patron update searching for dup ident values: " .
491 $patron->ident_type . ':' . $patron->ident_value);
493 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
495 my $dups = $session->request(
496 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
499 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
506 sub _add_update_addresses {
510 my $new_patron = shift;
514 my $current_id; # id of the address before creation
516 for my $address (@{$patron->addresses()}) {
518 next unless ref $address;
519 $current_id = $address->id();
521 if( $patron->billing_address() and
522 $patron->billing_address() == $current_id ) {
523 $logger->info("setting billing addr to $current_id");
524 $new_patron->billing_address($address->id());
525 $new_patron->ischanged(1);
528 if( $patron->mailing_address() and
529 $patron->mailing_address() == $current_id ) {
530 $new_patron->mailing_address($address->id());
531 $logger->info("setting mailing addr to $current_id");
532 $new_patron->ischanged(1);
536 if($address->isnew()) {
538 $address->usr($new_patron->id());
540 ($address, $evt) = _add_address($session,$address);
541 return (undef, $evt) if $evt;
543 # we need to get the new id
544 if( $patron->billing_address() and
545 $patron->billing_address() == $current_id ) {
546 $new_patron->billing_address($address->id());
547 $logger->info("setting billing addr to $current_id");
548 $new_patron->ischanged(1);
551 if( $patron->mailing_address() and
552 $patron->mailing_address() == $current_id ) {
553 $new_patron->mailing_address($address->id());
554 $logger->info("setting mailing addr to $current_id");
555 $new_patron->ischanged(1);
558 } elsif($address->ischanged() ) {
560 ($address, $evt) = _update_address($session, $address);
561 return (undef, $evt) if $evt;
563 } elsif($address->isdeleted() ) {
565 if( $address->id() == $new_patron->mailing_address() ) {
566 $new_patron->clear_mailing_address();
567 ($new_patron, $evt) = _update_patron($session, $new_patron);
568 return (undef, $evt) if $evt;
571 if( $address->id() == $new_patron->billing_address() ) {
572 $new_patron->clear_billing_address();
573 ($new_patron, $evt) = _update_patron($session, $new_patron);
574 return (undef, $evt) if $evt;
577 $evt = _delete_address($session, $address);
578 return (undef, $evt) if $evt;
582 return ( $new_patron, undef );
586 # adds an address to the db and returns the address with new id
588 my($session, $address) = @_;
589 $address->clear_id();
591 $logger->info("Creating new address at street ".$address->street1);
593 # put the address into the database
594 my $id = $session->request(
595 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
596 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
599 return ($address, undef);
603 sub _update_address {
604 my( $session, $address ) = @_;
606 $logger->info("Updating address ".$address->id." in the DB");
608 my $stat = $session->request(
609 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
611 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
612 return ($address, undef);
617 sub _add_update_cards {
621 my $new_patron = shift;
625 my $virtual_id; #id of the card before creation
626 for my $card (@{$patron->cards()}) {
628 $card->usr($new_patron->id());
630 if(ref($card) and $card->isnew()) {
632 $virtual_id = $card->id();
633 ( $card, $evt ) = _add_card($session,$card);
634 return (undef, $evt) if $evt;
636 #if(ref($patron->card)) { $patron->card($patron->card->id); }
637 if($patron->card() == $virtual_id) {
638 $new_patron->card($card->id());
639 $new_patron->ischanged(1);
642 } elsif( ref($card) and $card->ischanged() ) {
643 $evt = _update_card($session, $card);
644 return (undef, $evt) if $evt;
648 return ( $new_patron, undef );
652 # adds an card to the db and returns the card with new id
654 my( $session, $card ) = @_;
657 $logger->info("Adding new patron card ".$card->barcode);
659 my $id = $session->request(
660 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
661 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
662 $logger->info("Successfully created patron card $id");
665 return ( $card, undef );
669 # returns event on error. returns undef otherwise
671 my( $session, $card ) = @_;
672 $logger->info("Updating patron card ".$card->id);
674 my $stat = $session->request(
675 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
676 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
683 # returns event on error. returns undef otherwise
684 sub _delete_address {
685 my( $session, $address ) = @_;
687 $logger->info("Deleting address ".$address->id." from DB");
689 my $stat = $session->request(
690 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
692 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
698 sub _add_survey_responses {
699 my ($session, $patron, $new_patron) = @_;
701 $logger->info( "Updating survey responses for patron ".$new_patron->id );
703 my $responses = $patron->survey_responses;
707 $_->usr($new_patron->id) for (@$responses);
709 my $evt = $U->simplereq( "open-ils.circ",
710 "open-ils.circ.survey.submit.user_id", $responses );
712 return (undef, $evt) if defined($U->event_code($evt));
716 return ( $new_patron, undef );
720 sub _create_stat_maps {
722 my($session, $user_session, $patron, $new_patron) = @_;
724 my $maps = $patron->stat_cat_entries();
726 for my $map (@$maps) {
728 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
730 if ($map->isdeleted()) {
731 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
733 } elsif ($map->isnew()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
739 $map->target_usr($new_patron->id);
742 $logger->info("Updating stat entry with method $method and map $map");
744 my $stat = $session->request($method, $map)->gather(1);
745 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
749 return ($new_patron, undef);
752 sub _create_perm_maps {
754 my($session, $user_session, $patron, $new_patron) = @_;
756 my $maps = $patron->permissions;
758 for my $map (@$maps) {
760 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
761 if ($map->isdeleted()) {
762 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
763 } elsif ($map->isnew()) {
764 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
769 $map->usr($new_patron->id);
771 #warn( "Updating permissions with method $method and session $user_session and map $map" );
772 $logger->info( "Updating permissions with method $method and map $map" );
774 my $stat = $session->request($method, $map)->gather(1);
775 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
779 return ($new_patron, undef);
783 __PACKAGE__->register_method(
784 method => "set_user_work_ous",
785 api_name => "open-ils.actor.user.work_ous.update",
788 sub set_user_work_ous {
794 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
797 my $session = $apputils->start_db_session();
799 for my $map (@$maps) {
801 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
802 if ($map->isdeleted()) {
803 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
804 } elsif ($map->isnew()) {
805 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
809 #warn( "Updating permissions with method $method and session $ses and map $map" );
810 $logger->info( "Updating work_ou map with method $method and map $map" );
812 my $stat = $session->request($method, $map)->gather(1);
813 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
817 $apputils->commit_db_session($session);
819 return scalar(@$maps);
823 __PACKAGE__->register_method(
824 method => "set_user_perms",
825 api_name => "open-ils.actor.user.permissions.update",
834 my $session = $apputils->start_db_session();
836 my( $user_obj, $evt ) = $U->checkses($ses);
839 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
842 $all = 1 if ($user_obj->super_user());
843 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
845 for my $map (@$maps) {
847 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
848 if ($map->isdeleted()) {
849 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
850 } elsif ($map->isnew()) {
851 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
855 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
857 #warn( "Updating permissions with method $method and session $ses and map $map" );
858 $logger->info( "Updating permissions with method $method and map $map" );
860 my $stat = $session->request($method, $map)->gather(1);
861 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
865 $apputils->commit_db_session($session);
867 return scalar(@$maps);
871 sub _create_standing_penalties {
873 my($session, $user_session, $patron, $new_patron) = @_;
875 my $maps = $patron->standing_penalties;
878 for my $map (@$maps) {
880 if ($map->isdeleted()) {
881 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
882 } elsif ($map->isnew()) {
883 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
889 $map->usr($new_patron->id);
891 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
893 my $stat = $session->request($method, $map)->gather(1);
894 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
897 return ($new_patron, undef);
902 __PACKAGE__->register_method(
903 method => "search_username",
904 api_name => "open-ils.actor.user.search.username",
907 sub search_username {
908 my($self, $client, $username) = @_;
909 return new_editor()->search_actor_user({usrname=>$username});
915 __PACKAGE__->register_method(
916 method => "user_retrieve_by_barcode",
917 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
919 sub user_retrieve_by_barcode {
920 my($self, $client, $user_session, $barcode) = @_;
922 $logger->debug("Searching for user with barcode $barcode");
923 my ($user_obj, $evt) = $apputils->checkses($user_session);
926 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
928 "open-ils.cstore.direct.actor.card.search.atomic",
929 { barcode => $barcode }
932 if(!$card || !$card->[0]) {
933 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
937 my $user = flesh_user($card->usr());
939 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
942 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
949 __PACKAGE__->register_method(
950 method => "get_user_by_id",
951 api_name => "open-ils.actor.user.retrieve",);
954 my ($self, $client, $auth, $id) = @_;
955 my $e = new_editor(authtoken=>$auth);
956 return $e->event unless $e->checkauth;
957 my $user = $e->retrieve_actor_user($id)
959 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
965 __PACKAGE__->register_method(
966 method => "get_org_types",
967 api_name => "open-ils.actor.org_types.retrieve",);
970 return $U->get_org_types();
975 __PACKAGE__->register_method(
976 method => "get_user_ident_types",
977 api_name => "open-ils.actor.user.ident_types.retrieve",
980 sub get_user_ident_types {
981 return $ident_types if $ident_types;
982 return $ident_types =
983 new_editor()->retrieve_all_config_identification_type();
989 __PACKAGE__->register_method(
990 method => "get_org_unit",
991 api_name => "open-ils.actor.org_unit.retrieve",
995 my( $self, $client, $user_session, $org_id ) = @_;
996 my $e = new_editor(authtoken => $user_session);
998 return $e->event unless $e->checkauth;
999 $org_id = $e->requestor->ws_ou;
1001 my $o = $e->retrieve_actor_org_unit($org_id)
1002 or return $e->event;
1006 __PACKAGE__->register_method(
1007 method => "search_org_unit",
1008 api_name => "open-ils.actor.org_unit_list.search",
1011 sub search_org_unit {
1013 my( $self, $client, $field, $value ) = @_;
1015 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1017 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1018 { $field => $value } );
1024 # build the org tree
1026 __PACKAGE__->register_method(
1027 method => "get_org_tree",
1028 api_name => "open-ils.actor.org_tree.retrieve",
1030 note => "Returns the entire org tree structure",
1034 my( $self, $client) = @_;
1035 return $U->get_org_tree();
1039 # turns an org list into an org tree
1040 sub build_org_tree {
1042 my( $self, $orglist) = @_;
1044 return $orglist unless ref $orglist;
1045 return $$orglist[0] if @$orglist == 1;
1048 $a->ou_type <=> $b->ou_type ||
1049 $a->name cmp $b->name } @$orglist;
1051 for my $org (@list) {
1053 next unless ($org and defined($org->parent_ou));
1054 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1055 next unless $parent;
1057 $parent->children([]) unless defined($parent->children);
1058 push( @{$parent->children}, $org );
1066 __PACKAGE__->register_method(
1067 method => "get_org_descendants",
1068 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1071 # depth is optional. org_unit is the id
1072 sub get_org_descendants {
1073 my( $self, $client, $org_unit, $depth ) = @_;
1074 my $orglist = $apputils->simple_scalar_request(
1076 "open-ils.storage.actor.org_unit.descendants.atomic",
1077 $org_unit, $depth );
1078 return $self->build_org_tree($orglist);
1082 __PACKAGE__->register_method(
1083 method => "get_org_ancestors",
1084 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1087 # depth is optional. org_unit is the id
1088 sub get_org_ancestors {
1089 my( $self, $client, $org_unit, $depth ) = @_;
1090 my $orglist = $apputils->simple_scalar_request(
1092 "open-ils.storage.actor.org_unit.ancestors.atomic",
1093 $org_unit, $depth );
1094 return $self->build_org_tree($orglist);
1098 __PACKAGE__->register_method(
1099 method => "get_standings",
1100 api_name => "open-ils.actor.standings.retrieve"
1105 return $user_standings if $user_standings;
1106 return $user_standings =
1107 $apputils->simple_scalar_request(
1109 "open-ils.cstore.direct.config.standing.search.atomic",
1110 { id => { "!=" => undef } }
1116 __PACKAGE__->register_method(
1117 method => "get_my_org_path",
1118 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1121 sub get_my_org_path {
1122 my( $self, $client, $auth, $org_id ) = @_;
1123 my $e = new_editor(authtoken=>$auth);
1124 return $e->event unless $e->checkauth;
1125 $org_id = $e->requestor->ws_ou unless defined $org_id;
1127 return $apputils->simple_scalar_request(
1129 "open-ils.storage.actor.org_unit.full_path.atomic",
1134 __PACKAGE__->register_method(
1135 method => "patron_adv_search",
1136 api_name => "open-ils.actor.patron.search.advanced" );
1137 sub patron_adv_search {
1138 my( $self, $client, $auth, $search_hash,
1139 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1141 my $e = new_editor(authtoken=>$auth);
1142 return $e->event unless $e->checkauth;
1143 return $e->event unless $e->allowed('VIEW_USER');
1144 return $U->storagereq(
1145 "open-ils.storage.actor.user.crazy_search", $search_hash,
1146 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1150 __PACKAGE__->register_method(
1151 method => "update_passwd",
1153 api_name => "open-ils.actor.user.password.update");
1155 __PACKAGE__->register_method(
1156 method => "update_passwd",
1157 api_name => "open-ils.actor.user.username.update");
1159 __PACKAGE__->register_method(
1160 method => "update_passwd",
1161 api_name => "open-ils.actor.user.email.update");
1164 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1165 my $e = new_editor(xact=>1, authtoken=>$auth);
1166 return $e->die_event unless $e->checkauth;
1168 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1169 or return $e->die_event;
1170 my $api = $self->api_name;
1172 if( $api =~ /password/o ) {
1174 # make sure the original password matches the in-database password
1175 return OpenILS::Event->new('INCORRECT_PASSWORD')
1176 if md5_hex($orig_pw) ne $db_user->passwd;
1177 $db_user->passwd($new_val);
1181 # if we don't clear the password, the user will be updated with
1182 # a hashed version of the hashed version of their password
1183 $db_user->clear_passwd;
1185 if( $api =~ /username/o ) {
1187 # make sure no one else has this username
1188 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1189 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1190 $db_user->usrname($new_val);
1192 } elsif( $api =~ /email/o ) {
1193 $db_user->email($new_val);
1197 $e->update_actor_user($db_user) or return $e->die_event;
1205 __PACKAGE__->register_method(
1206 method => "check_user_perms",
1207 api_name => "open-ils.actor.user.perm.check",
1208 notes => <<" NOTES");
1209 Takes a login session, user id, an org id, and an array of perm type strings. For each
1210 perm type, if the user does *not* have the given permission it is added
1211 to a list which is returned from the method. If all permissions
1212 are allowed, an empty list is returned
1213 if the logged in user does not match 'user_id', then the logged in user must
1214 have VIEW_PERMISSION priveleges.
1217 sub check_user_perms {
1218 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1220 my( $staff, $evt ) = $apputils->checkses($login_session);
1221 return $evt if $evt;
1223 if($staff->id ne $user_id) {
1224 if( $evt = $apputils->check_perms(
1225 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1231 for my $perm (@$perm_types) {
1232 if($apputils->check_perms($user_id, $org_id, $perm)) {
1233 push @not_allowed, $perm;
1237 return \@not_allowed
1240 __PACKAGE__->register_method(
1241 method => "check_user_perms2",
1242 api_name => "open-ils.actor.user.perm.check.multi_org",
1244 Checks the permissions on a list of perms and orgs for a user
1245 @param authtoken The login session key
1246 @param user_id The id of the user to check
1247 @param orgs The array of org ids
1248 @param perms The array of permission names
1249 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1250 if the logged in user does not match 'user_id', then the logged in user must
1251 have VIEW_PERMISSION priveleges.
1254 sub check_user_perms2 {
1255 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1257 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1258 $authtoken, $user_id, 'VIEW_PERMISSION' );
1259 return $evt if $evt;
1262 for my $org (@$orgs) {
1263 for my $perm (@$perms) {
1264 if($apputils->check_perms($user_id, $org, $perm)) {
1265 push @not_allowed, [ $org, $perm ];
1270 return \@not_allowed
1274 __PACKAGE__->register_method(
1275 method => 'check_user_perms3',
1276 api_name => 'open-ils.actor.user.perm.highest_org',
1278 Returns the highest org unit id at which a user has a given permission
1279 If the requestor does not match the target user, the requestor must have
1280 'VIEW_PERMISSION' rights at the home org unit of the target user
1281 @param authtoken The login session key
1282 @param userid The id of the user in question
1283 @param perm The permission to check
1284 @return The org unit highest in the org tree within which the user has
1285 the requested permission
1288 sub check_user_perms3 {
1289 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1291 my( $staff, $target, $org, $evt );
1293 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1294 $authtoken, $userid, 'VIEW_PERMISSION' );
1295 return $evt if $evt;
1297 my $tree = $self->get_org_tree();
1298 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1302 sub _find_highest_perm_org {
1303 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1304 my $org = $apputils->find_org($org_tree, $start_org );
1308 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1310 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1317 __PACKAGE__->register_method(
1318 method => 'check_user_work_perms',
1319 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1323 Returns a set of org units which represent the highest orgs in
1324 the org tree where the user has the requested permission. The
1325 purpose of this method is to return the smallest set of org units
1326 which represent the full expanse of the user's ability to perform
1327 the requested action. The user whose perms this method should
1328 check is implied by the authtoken. /,
1330 {desc => 'authtoken', type => 'string'},
1331 {desc => 'permission name', type => 'string'},
1332 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1334 return => {desc => 'An array of org IDs'}
1338 sub check_user_work_perms {
1339 my($self, $conn, $auth, $perm, $options) = @_;
1340 my $e = new_editor(authtoken=>$auth);
1341 return $e->event unless $e->checkauth;
1342 return $U->find_highest_work_orgs($e, $perm, $options);
1345 __PACKAGE__->register_method(
1346 method => 'check_user_perms4',
1347 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1349 Returns the highest org unit id at which a user has a given permission
1350 If the requestor does not match the target user, the requestor must have
1351 'VIEW_PERMISSION' rights at the home org unit of the target user
1352 @param authtoken The login session key
1353 @param userid The id of the user in question
1354 @param perms An array of perm names to check
1355 @return An array of orgId's representing the org unit
1356 highest in the org tree within which the user has the requested permission
1357 The arrah of orgId's has matches the order of the perms array
1360 sub check_user_perms4 {
1361 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1363 my( $staff, $target, $org, $evt );
1365 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1366 $authtoken, $userid, 'VIEW_PERMISSION' );
1367 return $evt if $evt;
1370 return [] unless ref($perms);
1371 my $tree = $self->get_org_tree();
1373 for my $p (@$perms) {
1374 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1382 __PACKAGE__->register_method(
1383 method => "user_fines_summary",
1384 api_name => "open-ils.actor.user.fines.summary",
1385 notes => <<" NOTES");
1386 Returns a short summary of the users total open fines, excluding voided fines
1387 Params are login_session, user_id
1388 Returns a 'mous' object.
1391 sub user_fines_summary {
1392 my( $self, $client, $auth, $user_id ) = @_;
1393 my $e = new_editor(authtoken=>$auth);
1394 return $e->event unless $e->checkauth;
1395 my $user = $e->retrieve_actor_user($user_id)
1396 or return $e->event;
1398 if( $user_id ne $e->requestor->id ) {
1399 return $e->event unless
1400 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1403 # run this inside a transaction to prevent replication delay errors
1404 my $ses = $U->start_db_session();
1405 my $s = $ses->request(
1406 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1407 $U->rollback_db_session($ses);
1414 __PACKAGE__->register_method(
1415 method => "user_transactions",
1416 api_name => "open-ils.actor.user.transactions",
1417 notes => <<" NOTES");
1418 Returns a list of open user transactions (mbts objects);
1419 Params are login_session, user_id
1420 Optional third parameter is the transactions type. defaults to all
1423 __PACKAGE__->register_method(
1424 method => "user_transactions",
1425 api_name => "open-ils.actor.user.transactions.have_charge",
1426 notes => <<" NOTES");
1427 Returns a list of all open user transactions (mbts objects) that have an initial charge
1428 Params are login_session, user_id
1429 Optional third parameter is the transactions type. defaults to all
1432 __PACKAGE__->register_method(
1433 method => "user_transactions",
1434 api_name => "open-ils.actor.user.transactions.have_balance",
1435 notes => <<" NOTES");
1436 Returns a list of all open user transactions (mbts objects) that have a balance
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.fleshed",
1444 notes => <<" NOTES");
1445 Returns an object/hash of transaction, circ, title where transaction = an open
1446 user transactions (mbts objects), circ is the attached circluation, and title
1447 is the title the circ points to
1448 Params are login_session, user_id
1449 Optional third parameter is the transactions type. defaults to all
1452 __PACKAGE__->register_method(
1453 method => "user_transactions",
1454 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1455 notes => <<" NOTES");
1456 Returns an object/hash of transaction, circ, title where transaction = an open
1457 user transactions that has an initial charge (mbts objects), circ is the
1458 attached circluation, and title 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_balance.fleshed",
1466 notes => <<" NOTES");
1467 Returns an object/hash of transaction, circ, title where transaction = an open
1468 user transaction that has a balance (mbts objects), circ is the attached
1469 circluation, and title is the title the circ points to
1470 Params are login_session, user_id
1471 Optional third parameter is the transaction type. defaults to all
1474 __PACKAGE__->register_method(
1475 method => "user_transactions",
1476 api_name => "open-ils.actor.user.transactions.count",
1477 notes => <<" NOTES");
1478 Returns an object/hash of transaction, circ, title where transaction = an open
1479 user transactions (mbts objects), circ is the attached circluation, and title
1480 is the title the circ points to
1481 Params are login_session, user_id
1482 Optional third parameter is the transactions type. defaults to all
1485 __PACKAGE__->register_method(
1486 method => "user_transactions",
1487 api_name => "open-ils.actor.user.transactions.have_charge.count",
1488 notes => <<" NOTES");
1489 Returns an object/hash of transaction, circ, title where transaction = an open
1490 user transactions that has an initial charge (mbts objects), circ is the
1491 attached circluation, and title is the title the circ points to
1492 Params are login_session, user_id
1493 Optional third parameter is the transactions type. defaults to all
1496 __PACKAGE__->register_method(
1497 method => "user_transactions",
1498 api_name => "open-ils.actor.user.transactions.have_balance.count",
1499 notes => <<" NOTES");
1500 Returns an object/hash of transaction, circ, title where transaction = an open
1501 user transaction that has a balance (mbts objects), circ is the attached
1502 circluation, and title is the title the circ points to
1503 Params are login_session, user_id
1504 Optional third parameter is the transaction type. defaults to all
1507 __PACKAGE__->register_method(
1508 method => "user_transactions",
1509 api_name => "open-ils.actor.user.transactions.have_balance.total",
1510 notes => <<" NOTES");
1511 Returns an object/hash of transaction, circ, title where transaction = an open
1512 user transaction that has a balance (mbts objects), circ is the attached
1513 circluation, and title is the title the circ points to
1514 Params are login_session, user_id
1515 Optional third parameter is the transaction type. defaults to all
1520 sub user_transactions {
1521 my( $self, $client, $login_session, $user_id, $type ) = @_;
1523 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1524 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1525 return $evt if $evt;
1527 my $api = $self->api_name();
1531 if(defined($type)) { @xact = (xact_type => $type);
1533 } else { @xact = (); }
1536 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1537 ->run($login_session => $user_id => $type);
1539 if($api =~ /have_charge/o) {
1541 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1543 } elsif($api =~ /have_balance/o) {
1545 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1548 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1552 if($api =~ /total/o) {
1554 for my $t (@$trans) {
1555 $total += $t->balance_owed;
1558 $logger->debug("Total balance owed by user $user_id: $total");
1562 if($api =~ /count/o) { return scalar @$trans; }
1563 if($api !~ /fleshed/o) { return $trans; }
1566 for my $t (@$trans) {
1568 if( $t->xact_type ne 'circulation' ) {
1569 push @resp, {transaction => $t};
1573 my $circ = $apputils->simple_scalar_request(
1575 "open-ils.cstore.direct.action.circulation.retrieve",
1580 my $title = $apputils->simple_scalar_request(
1582 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1583 $circ->target_copy );
1587 my $u = OpenILS::Utils::ModsParser->new();
1588 $u->start_mods_batch($title->marc());
1589 my $mods = $u->finish_mods_batch();
1590 $mods->doc_id($title->id) if $mods;
1592 push @resp, {transaction => $t, circ => $circ, record => $mods };
1600 __PACKAGE__->register_method(
1601 method => "user_transaction_retrieve",
1602 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1604 notes => <<" NOTES");
1605 Returns a fleshedtransaction record
1607 __PACKAGE__->register_method(
1608 method => "user_transaction_retrieve",
1609 api_name => "open-ils.actor.user.transaction.retrieve",
1611 notes => <<" NOTES");
1612 Returns a transaction record
1614 sub user_transaction_retrieve {
1615 my( $self, $client, $login_session, $bill_id ) = @_;
1617 # XXX I think I'm deprecated... make sure
1619 my $trans = $apputils->simple_scalar_request(
1621 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1625 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1626 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1627 return $evt if $evt;
1629 my $api = $self->api_name();
1630 if($api !~ /fleshed/o) { return $trans; }
1632 if( $trans->xact_type ne 'circulation' ) {
1633 $logger->debug("Returning non-circ transaction");
1634 return {transaction => $trans};
1637 my $circ = $apputils->simple_scalar_request(
1639 "open-ils..direct.action.circulation.retrieve",
1642 return {transaction => $trans} unless $circ;
1643 $logger->debug("Found the circ transaction");
1645 my $title = $apputils->simple_scalar_request(
1647 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1648 $circ->target_copy );
1650 return {transaction => $trans, circ => $circ } unless $title;
1651 $logger->debug("Found the circ title");
1655 my $u = OpenILS::Utils::ModsParser->new();
1656 $u->start_mods_batch($title->marc());
1657 $mods = $u->finish_mods_batch();
1659 if ($title->id == OILS_PRECAT_RECORD) {
1660 my $copy = $apputils->simple_scalar_request(
1662 "open-ils.cstore.direct.asset.copy.retrieve",
1663 $circ->target_copy );
1665 $mods = new Fieldmapper::metabib::virtual_record;
1666 $mods->doc_id(OILS_PRECAT_RECORD);
1667 $mods->title($copy->dummy_title);
1668 $mods->author($copy->dummy_author);
1672 $logger->debug("MODSized the circ title");
1674 return {transaction => $trans, circ => $circ, record => $mods };
1678 __PACKAGE__->register_method(
1679 method => "hold_request_count",
1680 api_name => "open-ils.actor.user.hold_requests.count",
1682 notes => <<" NOTES");
1683 Returns hold ready/total counts
1685 sub hold_request_count {
1686 my( $self, $client, $login_session, $userid ) = @_;
1688 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1689 $login_session, $userid, 'VIEW_HOLD' );
1690 return $evt if $evt;
1693 my $holds = $apputils->simple_scalar_request(
1695 "open-ils.cstore.direct.action.hold_request.search.atomic",
1698 fulfillment_time => {"=" => undef },
1699 cancel_time => undef,
1704 for my $h (@$holds) {
1705 next unless $h->capture_time and $h->current_copy;
1707 my $copy = $apputils->simple_scalar_request(
1709 "open-ils.cstore.direct.asset.copy.retrieve",
1713 if ($copy and $copy->status == 8) {
1718 return { total => scalar(@$holds), ready => scalar(@ready) };
1722 __PACKAGE__->register_method(
1723 method => "checkedout_count",
1724 api_name => "open-ils.actor.user.checked_out.count__",
1726 notes => <<" NOTES");
1727 Returns a transaction record
1731 sub checkedout_count {
1732 my( $self, $client, $login_session, $userid ) = @_;
1734 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1735 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1736 return $evt if $evt;
1738 my $circs = $apputils->simple_scalar_request(
1740 "open-ils.cstore.direct.action.circulation.search.atomic",
1741 { usr => $userid, stop_fines => undef }
1742 #{ usr => $userid, checkin_time => {"=" => undef } }
1745 my $parser = DateTime::Format::ISO8601->new;
1748 for my $c (@$circs) {
1749 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1750 my $due = $due_dt->epoch;
1752 if ($due < DateTime->today->epoch) {
1757 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1761 __PACKAGE__->register_method(
1762 method => "checked_out",
1763 api_name => "open-ils.actor.user.checked_out",
1766 Returns a structure of circulations objects sorted by
1767 out, overdue, lost, claims_returned, long_overdue.
1768 A list of IDs are returned of each type.
1769 lost, long_overdue, and claims_returned circ will not
1770 be "finished" (there is an outstanding balance or some
1771 other pending action on the circ).
1773 The .count method also includes a 'total' field which
1774 sums all "open" circs
1778 __PACKAGE__->register_method(
1779 method => "checked_out",
1780 api_name => "open-ils.actor.user.checked_out.count",
1782 signature => q/@see open-ils.actor.user.checked_out/
1786 my( $self, $conn, $auth, $userid ) = @_;
1788 my $e = new_editor(authtoken=>$auth);
1789 return $e->event unless $e->checkauth;
1791 if( $userid ne $e->requestor->id ) {
1792 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1795 my $count = $self->api_name =~ /count/;
1796 return _checked_out( $count, $e, $userid );
1800 my( $iscount, $e, $userid ) = @_;
1803 my $meth = 'open-ils.storage.actor.user.checked_out';
1804 $meth = "$meth.count" if $iscount;
1805 return $U->storagereq($meth, $userid);
1807 # XXX Old code - moved to storage
1808 #------------------------------------------------------------------------------
1809 #------------------------------------------------------------------------------
1810 my $circs = $e->search_action_circulation(
1811 { usr => $userid, checkin_time => undef });
1813 my $parser = DateTime::Format::ISO8601->new;
1815 # split the circs up into overdue and not-overdue circs
1817 for my $c (@$circs) {
1818 if( $c->due_date ) {
1819 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1820 my $due = $due_dt->epoch;
1821 if ($due < DateTime->today->epoch) {
1831 my( @open, @od, @lost, @cr, @lo );
1833 while (my $c = shift(@out)) {
1834 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1835 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1836 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1837 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1840 while (my $c = shift(@overdue)) {
1841 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1842 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1843 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1844 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1849 total => @open + @od + @lost + @cr + @lo,
1850 out => scalar(@open),
1851 overdue => scalar(@od),
1852 lost => scalar(@lost),
1853 claims_returned => scalar(@cr),
1854 long_overdue => scalar(@lo)
1862 claims_returned => \@cr,
1863 long_overdue => \@lo
1868 sub _checked_out_WHAT {
1869 my( $iscount, $e, $userid ) = @_;
1871 my $circs = $e->search_action_circulation(
1872 { usr => $userid, stop_fines => undef });
1874 my $mcircs = $e->search_action_circulation(
1877 checkin_time => undef,
1878 xact_finish => undef,
1882 push( @$circs, @$mcircs );
1884 my $parser = DateTime::Format::ISO8601->new;
1886 # split the circs up into overdue and not-overdue circs
1888 for my $c (@$circs) {
1889 if( $c->due_date ) {
1890 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1891 my $due = $due_dt->epoch;
1892 if ($due < DateTime->today->epoch) {
1893 push @overdue, $c->id;
1902 # grab all of the lost, claims-returned, and longoverdue circs
1903 #my $open = $e->search_action_circulation(
1904 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1907 # these items have stop_fines, but no xact_finish, so money
1908 # is owed on them and they have not been checked in
1909 my $open = $e->search_action_circulation(
1912 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1913 xact_finish => undef,
1914 checkin_time => undef,
1919 my( @lost, @cr, @lo );
1920 for my $c (@$open) {
1921 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1922 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1923 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1929 total => @$circs + @lost + @cr + @lo,
1930 out => scalar(@out),
1931 overdue => scalar(@overdue),
1932 lost => scalar(@lost),
1933 claims_returned => scalar(@cr),
1934 long_overdue => scalar(@lo)
1940 overdue => \@overdue,
1942 claims_returned => \@cr,
1943 long_overdue => \@lo
1949 __PACKAGE__->register_method(
1950 method => "checked_in_with_fines",
1951 api_name => "open-ils.actor.user.checked_in_with_fines",
1953 signature => q/@see open-ils.actor.user.checked_out/
1955 sub checked_in_with_fines {
1956 my( $self, $conn, $auth, $userid ) = @_;
1958 my $e = new_editor(authtoken=>$auth);
1959 return $e->event unless $e->checkauth;
1961 if( $userid ne $e->requestor->id ) {
1962 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1965 # money is owed on these items and they are checked in
1966 my $open = $e->search_action_circulation(
1969 xact_finish => undef,
1970 checkin_time => { "!=" => undef },
1975 my( @lost, @cr, @lo );
1976 for my $c (@$open) {
1977 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1978 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1979 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1984 claims_returned => \@cr,
1985 long_overdue => \@lo
1997 __PACKAGE__->register_method(
1998 method => "user_transaction_history",
1999 api_name => "open-ils.actor.user.transactions.history",
2001 notes => <<" NOTES");
2002 Returns a list of billable transaction ids for a user, optionally by type
2004 __PACKAGE__->register_method(
2005 method => "user_transaction_history",
2006 api_name => "open-ils.actor.user.transactions.history.have_charge",
2008 notes => <<" NOTES");
2009 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2011 __PACKAGE__->register_method(
2012 method => "user_transaction_history",
2013 api_name => "open-ils.actor.user.transactions.history.have_balance",
2015 notes => <<" NOTES");
2016 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2018 __PACKAGE__->register_method(
2019 method => "user_transaction_history",
2020 api_name => "open-ils.actor.user.transactions.history.still_open",
2022 notes => <<" NOTES");
2023 Returns a list of billable transaction ids for a user that are not finished
2025 __PACKAGE__->register_method(
2026 method => "user_transaction_history",
2027 api_name => "open-ils.actor.user.transactions.history.have_bill",
2029 notes => <<" NOTES");
2030 Returns a list of billable transaction ids for a user that has billings
2036 sub _user_transaction_history {
2037 my( $self, $client, $login_session, $user_id, $type ) = @_;
2039 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2040 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2041 return $evt if $evt;
2043 my $api = $self->api_name();
2048 @xact = (xact_type => $type) if(defined($type));
2049 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2050 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2052 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2054 my $trans = $apputils->simple_scalar_request(
2056 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2057 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2059 return [ map { $_->id } @$trans ];
2063 =head SEE APPUTILS.PM
2068 for my $x (@xacts) {
2069 my $s = new Fieldmapper::money::billable_transaction_summary;
2072 $s->xact_start( $x->xact_start );
2073 $s->xact_finish( $x->xact_finish );
2077 for my $b (@{ $x->billings }) {
2078 next if ($U->is_true($b->voided));
2079 $to += ($b->amount * 100);
2080 $lb ||= $b->billing_ts;
2081 if ($b->billing_ts ge $lb) {
2082 $lb = $b->billing_ts;
2083 $s->last_billing_note($b->note);
2084 $s->last_billing_ts($b->billing_ts);
2085 $s->last_billing_type($b->billing_type);
2089 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2093 for my $p (@{ $x->payments }) {
2094 next if ($U->is_true($p->voided));
2095 $tp += ($p->amount * 100);
2096 $lp ||= $p->payment_ts;
2097 if ($p->payment_ts ge $lp) {
2098 $lp = $p->payment_ts;
2099 $s->last_payment_note($p->note);
2100 $s->last_payment_ts($p->payment_ts);
2101 $s->last_payment_type($p->payment_type);
2104 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2106 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2108 $s->xact_type( 'grocery' ) if ($x->grocery);
2109 $s->xact_type( 'circulation' ) if ($x->circulation);
2118 sub user_transaction_history {
2119 my( $self, $conn, $auth, $userid, $type ) = @_;
2121 # run inside of a transaction to prevent replication delays
2122 my $e = new_editor(xact=>1, authtoken=>$auth);
2123 return $e->die_event unless $e->checkauth;
2125 if( $e->requestor->id ne $userid ) {
2126 return $e->die_event
2127 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2130 my $api = $self->api_name;
2131 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2133 my @xacts = @{ $e->search_money_billable_transaction(
2134 [ { usr => $userid, @xact_finish },
2136 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2137 order_by => { mbt => 'xact_start DESC' },
2145 #my @mbts = _make_mbts( @xacts );
2146 my @mbts = $U->make_mbts( @xacts );
2148 if(defined($type)) {
2149 @mbts = grep { $_->xact_type eq $type } @mbts;
2152 if($api =~ /have_balance/o) {
2153 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2156 if($api =~ /have_charge/o) {
2157 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2160 if($api =~ /have_bill/o) {
2161 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2169 __PACKAGE__->register_method(
2170 method => "user_perms",
2171 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2173 notes => <<" NOTES");
2174 Returns a list of permissions
2177 my( $self, $client, $authtoken, $user ) = @_;
2179 my( $staff, $evt ) = $apputils->checkses($authtoken);
2180 return $evt if $evt;
2182 $user ||= $staff->id;
2184 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2188 return $apputils->simple_scalar_request(
2190 "open-ils.storage.permission.user_perms.atomic",
2194 __PACKAGE__->register_method(
2195 method => "retrieve_perms",
2196 api_name => "open-ils.actor.permissions.retrieve",
2197 notes => <<" NOTES");
2198 Returns a list of permissions
2200 sub retrieve_perms {
2201 my( $self, $client ) = @_;
2202 return $apputils->simple_scalar_request(
2204 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2205 { id => { '!=' => undef } }
2209 __PACKAGE__->register_method(
2210 method => "retrieve_groups",
2211 api_name => "open-ils.actor.groups.retrieve",
2212 notes => <<" NOTES");
2213 Returns a list of user groupss
2215 sub retrieve_groups {
2216 my( $self, $client ) = @_;
2217 return new_editor()->retrieve_all_permission_grp_tree();
2220 __PACKAGE__->register_method(
2221 method => "retrieve_org_address",
2222 api_name => "open-ils.actor.org_unit.address.retrieve",
2223 notes => <<' NOTES');
2224 Returns an org_unit address by ID
2225 @param An org_address ID
2227 sub retrieve_org_address {
2228 my( $self, $client, $id ) = @_;
2229 return $apputils->simple_scalar_request(
2231 "open-ils.cstore.direct.actor.org_address.retrieve",
2236 __PACKAGE__->register_method(
2237 method => "retrieve_groups_tree",
2238 api_name => "open-ils.actor.groups.tree.retrieve",
2239 notes => <<" NOTES");
2240 Returns a list of user groups
2242 sub retrieve_groups_tree {
2243 my( $self, $client ) = @_;
2244 return new_editor()->search_permission_grp_tree(
2249 flesh_fields => { pgt => ["children"] },
2250 order_by => { pgt => 'name'}
2257 # turns an org list into an org tree
2259 sub build_group_tree {
2261 my( $self, $grplist) = @_;
2263 return $grplist unless (
2264 ref($grplist) and @$grplist > 1 );
2266 my @list = sort { $a->name cmp $b->name } @$grplist;
2269 for my $grp (@list) {
2271 if ($grp and !defined($grp->parent)) {
2275 my ($parent) = grep { $_->id == $grp->parent} @list;
2277 $parent->children([]) unless defined($parent->children);
2278 push( @{$parent->children}, $grp );
2286 __PACKAGE__->register_method(
2287 method => "add_user_to_groups",
2288 api_name => "open-ils.actor.user.set_groups",
2289 notes => <<" NOTES");
2290 Adds a user to one or more permission groups
2293 sub add_user_to_groups {
2294 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2296 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2297 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2298 return $evt if $evt;
2300 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2301 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2302 return $evt if $evt;
2304 $apputils->simplereq(
2306 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2308 for my $group (@$groups) {
2309 my $link = Fieldmapper::permission::usr_grp_map->new;
2311 $link->usr($userid);
2313 my $id = $apputils->simplereq(
2315 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2321 __PACKAGE__->register_method(
2322 method => "get_user_perm_groups",
2323 api_name => "open-ils.actor.user.get_groups",
2324 notes => <<" NOTES");
2325 Retrieve a user's permission groups.
2329 sub get_user_perm_groups {
2330 my( $self, $client, $authtoken, $userid ) = @_;
2332 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2333 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2334 return $evt if $evt;
2336 return $apputils->simplereq(
2338 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2342 __PACKAGE__->register_method(
2343 method => "get_user_work_ous",
2344 api_name => "open-ils.actor.user.get_work_ous",
2345 notes => <<" NOTES");
2346 Retrieve a user's work org units.
2348 __PACKAGE__->register_method(
2349 method => "get_user_work_ous",
2350 api_name => "open-ils.actor.user.get_work_ous.ids",
2351 notes => <<" NOTES");
2352 Retrieve a user's work org units.
2356 sub get_user_work_ous {
2357 my( $self, $client, $auth, $userid ) = @_;
2358 my $e = new_editor(authtoken=>$auth);
2359 return $e->event unless $e->checkauth;
2360 $userid ||= $e->requestor->id;
2362 if($e->requestor->id != $userid) {
2363 my $user = $e->retrieve_actor_user($userid)
2364 or return $e->event;
2365 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2368 return $e->search_permission_usr_work_ou_map({usr => $userid})
2369 unless $self->api_name =~ /.ids$/;
2371 # client just wants a list of org IDs
2372 return $U->get_user_work_ou_ids($e, $userid);
2378 __PACKAGE__->register_method (
2379 method => 'register_workstation',
2380 api_name => 'open-ils.actor.workstation.register.override',
2381 signature => q/@see open-ils.actor.workstation.register/);
2383 __PACKAGE__->register_method (
2384 method => 'register_workstation',
2385 api_name => 'open-ils.actor.workstation.register',
2387 Registers a new workstion in the system
2388 @param authtoken The login session key
2389 @param name The name of the workstation id
2390 @param owner The org unit that owns this workstation
2391 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2392 if the name is already in use.
2395 sub register_workstation {
2396 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2398 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2399 return $e->die_event unless $e->checkauth;
2400 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2401 my $existing = $e->search_actor_workstation({name => $name})->[0];
2405 if( $self->api_name =~ /override/o ) {
2406 # workstation with the given name exists.
2408 if($owner ne $existing->owning_lib) {
2409 # if necessary, update the owning_lib of the workstation
2411 $logger->info("changing owning lib of workstation ".$existing->id.
2412 " from ".$existing->owning_lib." to $owner");
2413 return $e->die_event unless
2414 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2416 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2418 $existing->owning_lib($owner);
2419 return $e->die_event unless $e->update_actor_workstation($existing);
2425 "attempt to register an existing workstation. returning existing ID");
2428 return $existing->id;
2431 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2435 my $ws = Fieldmapper::actor::workstation->new;
2436 $ws->owning_lib($owner);
2438 $e->create_actor_workstation($ws) or return $e->die_event;
2440 return $ws->id; # note: editor sets the id on the new object for us
2443 __PACKAGE__->register_method (
2444 method => 'workstation_list',
2445 api_name => 'open-ils.actor.workstation.list',
2447 Returns a list of workstations registered at the given location
2448 @param authtoken The login session key
2449 @param ids A list of org_unit.id's for the workstation owners
2452 sub workstation_list {
2453 my( $self, $conn, $authtoken, @orgs ) = @_;
2455 my $e = new_editor(authtoken=>$authtoken);
2456 return $e->event unless $e->checkauth;
2461 unless $e->allowed('REGISTER_WORKSTATION', $o);
2462 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2473 __PACKAGE__->register_method (
2474 method => 'fetch_patron_note',
2475 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 # XXX Make me retun undef if no user has the ID
2662 sub usrname_exists {
2663 my( $self, $conn, $auth, $usrname ) = @_;
2664 my $e = new_editor(authtoken=>$auth);
2665 return $e->event unless $e->checkauth;
2666 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2667 return $$a[0] if $a and @$a;
2671 __PACKAGE__->register_method(
2672 method => 'barcode_exists',
2673 api_name => 'open-ils.actor.barcode.exists',
2675 Returns 1 if the requested barcode exists, returns 0 otherwise
2679 sub barcode_exists {
2680 my( $self, $conn, $auth, $barcode ) = @_;
2681 my $e = new_editor(authtoken=>$auth);
2682 return $e->event unless $e->checkauth;
2683 my $card = $e->search_actor_card({barcode => $barcode});
2684 return 0 unless @$card;
2685 return $card->[0]->usr;
2689 __PACKAGE__->register_method(
2690 method => 'retrieve_net_levels',
2691 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2694 sub retrieve_net_levels {
2695 my( $self, $conn, $auth ) = @_;
2696 my $e = new_editor(authtoken=>$auth);
2697 return $e->event unless $e->checkauth;
2698 return $e->retrieve_all_config_net_access_level();
2702 __PACKAGE__->register_method(
2703 method => 'fetch_org_by_shortname',
2704 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2706 sub fetch_org_by_shortname {
2707 my( $self, $conn, $sname ) = @_;
2708 my $e = new_editor();
2709 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2710 return $e->event unless $org;
2715 __PACKAGE__->register_method(
2716 method => 'session_home_lib',
2717 api_name => 'open-ils.actor.session.home_lib',
2720 sub session_home_lib {
2721 my( $self, $conn, $auth ) = @_;
2722 my $e = new_editor(authtoken=>$auth);
2723 return undef unless $e->checkauth;
2724 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2725 return $org->shortname;
2728 __PACKAGE__->register_method(
2729 method => 'session_safe_token',
2730 api_name => 'open-ils.actor.session.safe_token',
2732 Returns a hashed session ID that is safe for export to the world.
2733 This safe token will expire after 1 hour of non-use.
2734 @param auth Active authentication token
2738 sub session_safe_token {
2739 my( $self, $conn, $auth ) = @_;
2740 my $e = new_editor(authtoken=>$auth);
2741 return undef unless $e->checkauth;
2743 my $safe_token = md5_hex($auth);
2745 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2747 # Add more like the following if needed...
2749 "safe-token-home_lib-shortname-$safe_token",
2750 $e->retrieve_actor_org_unit(
2751 $e->requestor->home_ou
2760 __PACKAGE__->register_method(
2761 method => 'safe_token_home_lib',
2762 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2764 Returns the home library shortname from the session
2765 asscociated with a safe token from generated by
2766 open-ils.actor.session.safe_token.
2767 @param safe_token Active safe token
2771 sub safe_token_home_lib {
2772 my( $self, $conn, $safe_token ) = @_;
2774 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2775 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2780 __PACKAGE__->register_method(
2781 method => 'slim_tree',
2782 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2785 my $tree = new_editor()->search_actor_org_unit(
2787 {"parent_ou" => undef },
2790 flesh_fields => { aou => ['children'] },
2791 order_by => { aou => 'name'},
2792 select => { aou => ["id","shortname", "name"]},
2797 return trim_tree($tree);
2803 return undef unless $tree;
2805 code => $tree->shortname,
2806 name => $tree->name,
2808 if( $tree->children and @{$tree->children} ) {
2809 $htree->{children} = [];
2810 for my $c (@{$tree->children}) {
2811 push( @{$htree->{children}}, trim_tree($c) );
2819 __PACKAGE__->register_method(
2820 method => "update_penalties",
2821 api_name => "open-ils.actor.user.penalties.update");
2822 sub update_penalties {
2823 my( $self, $conn, $auth, $userid ) = @_;
2824 my $e = new_editor(authtoken=>$auth);
2825 return $e->event unless $e->checkauth;
2826 $U->update_patron_penalties(
2828 patronid => $userid,
2835 __PACKAGE__->register_method(
2836 method => "user_retrieve_fleshed_by_id",
2837 api_name => "open-ils.actor.user.fleshed.retrieve",);
2839 sub user_retrieve_fleshed_by_id {
2840 my( $self, $client, $auth, $user_id, $fields ) = @_;
2841 my $e = new_editor(authtoken => $auth);
2842 return $e->event unless $e->checkauth;
2844 if( $e->requestor->id != $user_id ) {
2845 return $e->event unless $e->allowed('VIEW_USER');
2851 "standing_penalties",
2855 "stat_cat_entries" ];
2856 return new_flesh_user($user_id, $fields, $e);
2860 sub new_flesh_user {
2863 my $fields = shift || [];
2864 my $e = shift || new_editor(xact=>1);
2866 my $user = $e->retrieve_actor_user(
2871 "flesh_fields" => { "au" => $fields }
2874 ) or return $e->event;
2877 if( grep { $_ eq 'addresses' } @$fields ) {
2879 $user->addresses([]) unless @{$user->addresses};
2881 if( ref $user->billing_address ) {
2882 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2883 push( @{$user->addresses}, $user->billing_address );
2887 if( ref $user->mailing_address ) {
2888 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2889 push( @{$user->addresses}, $user->mailing_address );
2895 $user->clear_passwd();
2902 __PACKAGE__->register_method(
2903 method => "user_retrieve_parts",
2904 api_name => "open-ils.actor.user.retrieve.parts",);
2906 sub user_retrieve_parts {
2907 my( $self, $client, $auth, $user_id, $fields ) = @_;
2908 my $e = new_editor(authtoken => $auth);
2909 return $e->event unless $e->checkauth;
2910 if( $e->requestor->id != $user_id ) {
2911 return $e->event unless $e->allowed('VIEW_USER');
2914 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2915 push(@resp, $user->$_()) for(@$fields);
2921 __PACKAGE__->register_method(
2922 method => 'user_opt_in_enabled',
2923 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2925 @return 1 if user opt-in is globally enabled, 0 otherwise.
2928 sub user_opt_in_enabled {
2929 my($self, $conn) = @_;
2930 my $sc = OpenSRF::Utils::SettingsClient->new;
2931 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2936 __PACKAGE__->register_method(
2937 method => 'user_opt_in_at_org',
2938 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2940 @param $auth The auth token
2941 @param user_id The ID of the user to test
2942 @return 1 if the user has opted in at the specified org,
2943 event on error, and 0 otherwise. /);
2944 sub user_opt_in_at_org {
2945 my($self, $conn, $auth, $user_id) = @_;
2947 # see if we even need to enforce the opt-in value
2948 return 1 unless $self->user_opt_in_enabled;
2950 my $e = new_editor(authtoken => $auth);
2951 return $e->event unless $e->checkauth;
2952 my $org_id = $e->requestor->ws_ou;
2954 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2955 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2957 # user is automatically opted-in at the home org
2958 return 1 if $user->home_ou eq $org_id;
2960 my $vals = $e->search_actor_usr_org_unit_opt_in(
2961 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2967 __PACKAGE__->register_method(
2968 method => 'create_user_opt_in_at_org',
2969 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2971 @param $auth The auth token
2972 @param user_id The ID of the user to test
2973 @return The ID of the newly created object, event on error./);
2975 sub create_user_opt_in_at_org {
2976 my($self, $conn, $auth, $user_id) = @_;
2978 my $e = new_editor(authtoken => $auth, xact=>1);
2979 return $e->die_event unless $e->checkauth;
2980 my $org_id = $e->requestor->ws_ou;
2982 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2983 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2985 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2987 $opt_in->org_unit($org_id);
2988 $opt_in->usr($user_id);
2989 $opt_in->staff($e->requestor->id);
2990 $opt_in->opt_in_ts('now');
2991 $opt_in->opt_in_ws($e->requestor->wsid);
2993 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2994 or return $e->die_event;