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 ) = @_;
1051 my $orglist = $apputils->simple_scalar_request(
1053 "open-ils.storage.actor.org_unit.descendants.atomic",
1054 $org_unit, $depth );
1055 return $U->build_org_tree($orglist);
1059 __PACKAGE__->register_method(
1060 method => "get_org_ancestors",
1061 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1064 # depth is optional. org_unit is the id
1065 sub get_org_ancestors {
1066 my( $self, $client, $org_unit, $depth ) = @_;
1067 my $orglist = $apputils->simple_scalar_request(
1069 "open-ils.storage.actor.org_unit.ancestors.atomic",
1070 $org_unit, $depth );
1071 return $U->build_org_tree($orglist);
1075 __PACKAGE__->register_method(
1076 method => "get_standings",
1077 api_name => "open-ils.actor.standings.retrieve"
1082 return $user_standings if $user_standings;
1083 return $user_standings =
1084 $apputils->simple_scalar_request(
1086 "open-ils.cstore.direct.config.standing.search.atomic",
1087 { id => { "!=" => undef } }
1093 __PACKAGE__->register_method(
1094 method => "get_my_org_path",
1095 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1098 sub get_my_org_path {
1099 my( $self, $client, $auth, $org_id ) = @_;
1100 my $e = new_editor(authtoken=>$auth);
1101 return $e->event unless $e->checkauth;
1102 $org_id = $e->requestor->ws_ou unless defined $org_id;
1104 return $apputils->simple_scalar_request(
1106 "open-ils.storage.actor.org_unit.full_path.atomic",
1111 __PACKAGE__->register_method(
1112 method => "patron_adv_search",
1113 api_name => "open-ils.actor.patron.search.advanced" );
1114 sub patron_adv_search {
1115 my( $self, $client, $auth, $search_hash,
1116 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1118 my $e = new_editor(authtoken=>$auth);
1119 return $e->event unless $e->checkauth;
1120 return $e->event unless $e->allowed('VIEW_USER');
1121 return $U->storagereq(
1122 "open-ils.storage.actor.user.crazy_search", $search_hash,
1123 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1127 __PACKAGE__->register_method(
1128 method => "update_passwd",
1130 api_name => "open-ils.actor.user.password.update");
1132 __PACKAGE__->register_method(
1133 method => "update_passwd",
1134 api_name => "open-ils.actor.user.username.update");
1136 __PACKAGE__->register_method(
1137 method => "update_passwd",
1138 api_name => "open-ils.actor.user.email.update");
1141 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1142 my $e = new_editor(xact=>1, authtoken=>$auth);
1143 return $e->die_event unless $e->checkauth;
1145 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1146 or return $e->die_event;
1147 my $api = $self->api_name;
1149 if( $api =~ /password/o ) {
1151 # make sure the original password matches the in-database password
1152 return OpenILS::Event->new('INCORRECT_PASSWORD')
1153 if md5_hex($orig_pw) ne $db_user->passwd;
1154 $db_user->passwd($new_val);
1158 # if we don't clear the password, the user will be updated with
1159 # a hashed version of the hashed version of their password
1160 $db_user->clear_passwd;
1162 if( $api =~ /username/o ) {
1164 # make sure no one else has this username
1165 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1166 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1167 $db_user->usrname($new_val);
1169 } elsif( $api =~ /email/o ) {
1170 $db_user->email($new_val);
1174 $e->update_actor_user($db_user) or return $e->die_event;
1182 __PACKAGE__->register_method(
1183 method => "check_user_perms",
1184 api_name => "open-ils.actor.user.perm.check",
1185 notes => <<" NOTES");
1186 Takes a login session, user id, an org id, and an array of perm type strings. For each
1187 perm type, if the user does *not* have the given permission it is added
1188 to a list which is returned from the method. If all permissions
1189 are allowed, an empty list is returned
1190 if the logged in user does not match 'user_id', then the logged in user must
1191 have VIEW_PERMISSION priveleges.
1194 sub check_user_perms {
1195 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1197 my( $staff, $evt ) = $apputils->checkses($login_session);
1198 return $evt if $evt;
1200 if($staff->id ne $user_id) {
1201 if( $evt = $apputils->check_perms(
1202 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1208 for my $perm (@$perm_types) {
1209 if($apputils->check_perms($user_id, $org_id, $perm)) {
1210 push @not_allowed, $perm;
1214 return \@not_allowed
1217 __PACKAGE__->register_method(
1218 method => "check_user_perms2",
1219 api_name => "open-ils.actor.user.perm.check.multi_org",
1221 Checks the permissions on a list of perms and orgs for a user
1222 @param authtoken The login session key
1223 @param user_id The id of the user to check
1224 @param orgs The array of org ids
1225 @param perms The array of permission names
1226 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1227 if the logged in user does not match 'user_id', then the logged in user must
1228 have VIEW_PERMISSION priveleges.
1231 sub check_user_perms2 {
1232 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1234 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1235 $authtoken, $user_id, 'VIEW_PERMISSION' );
1236 return $evt if $evt;
1239 for my $org (@$orgs) {
1240 for my $perm (@$perms) {
1241 if($apputils->check_perms($user_id, $org, $perm)) {
1242 push @not_allowed, [ $org, $perm ];
1247 return \@not_allowed
1251 __PACKAGE__->register_method(
1252 method => 'check_user_perms3',
1253 api_name => 'open-ils.actor.user.perm.highest_org',
1255 Returns the highest org unit id at which a user has a given permission
1256 If the requestor does not match the target user, the requestor must have
1257 'VIEW_PERMISSION' rights at the home org unit of the target user
1258 @param authtoken The login session key
1259 @param userid The id of the user in question
1260 @param perm The permission to check
1261 @return The org unit highest in the org tree within which the user has
1262 the requested permission
1265 sub check_user_perms3 {
1266 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1268 my( $staff, $target, $org, $evt );
1270 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1271 $authtoken, $userid, 'VIEW_PERMISSION' );
1272 return $evt if $evt;
1274 my $tree = $U->get_org_tree();
1275 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1279 __PACKAGE__->register_method(
1280 method => 'check_user_work_perms',
1281 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1285 Returns a set of org units which represent the highest orgs in
1286 the org tree where the user has the requested permission. The
1287 purpose of this method is to return the smallest set of org units
1288 which represent the full expanse of the user's ability to perform
1289 the requested action. The user whose perms this method should
1290 check is implied by the authtoken. /,
1292 {desc => 'authtoken', type => 'string'},
1293 {desc => 'permission name', type => 'string'},
1294 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1296 return => {desc => 'An array of org IDs'}
1300 sub check_user_work_perms {
1301 my($self, $conn, $auth, $perm, $options) = @_;
1302 my $e = new_editor(authtoken=>$auth);
1303 return $e->event unless $e->checkauth;
1304 return $U->find_highest_work_orgs($e, $perm, $options);
1307 __PACKAGE__->register_method(
1308 method => 'check_user_perms4',
1309 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1311 Returns the highest org unit id at which a user has a given permission
1312 If the requestor does not match the target user, the requestor must have
1313 'VIEW_PERMISSION' rights at the home org unit of the target user
1314 @param authtoken The login session key
1315 @param userid The id of the user in question
1316 @param perms An array of perm names to check
1317 @return An array of orgId's representing the org unit
1318 highest in the org tree within which the user has the requested permission
1319 The arrah of orgId's has matches the order of the perms array
1322 sub check_user_perms4 {
1323 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1325 my( $staff, $target, $org, $evt );
1327 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1328 $authtoken, $userid, 'VIEW_PERMISSION' );
1329 return $evt if $evt;
1332 return [] unless ref($perms);
1333 my $tree = $U->get_org_tree();
1335 for my $p (@$perms) {
1336 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1344 __PACKAGE__->register_method(
1345 method => "user_fines_summary",
1346 api_name => "open-ils.actor.user.fines.summary",
1348 notes => <<" NOTES");
1349 Returns a short summary of the users total open fines, excluding voided fines
1350 Params are login_session, user_id
1351 Returns a 'mous' object.
1354 sub user_fines_summary {
1355 my( $self, $client, $auth, $user_id ) = @_;
1356 my $e = new_editor(authtoken=>$auth);
1357 return $e->event unless $e->checkauth;
1358 my $user = $e->retrieve_actor_user($user_id)
1359 or return $e->event;
1361 if( $user_id ne $e->requestor->id ) {
1362 return $e->event unless
1363 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1366 # run this inside a transaction to prevent replication delay errors
1367 my $ses = $U->start_db_session();
1368 my $s = $ses->request(
1369 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1370 $U->rollback_db_session($ses);
1377 __PACKAGE__->register_method(
1378 method => "user_transactions",
1379 api_name => "open-ils.actor.user.transactions",
1380 notes => <<" NOTES");
1381 Returns a list of open user transactions (mbts objects);
1382 Params are login_session, user_id
1383 Optional third parameter is the transactions type. defaults to all
1386 __PACKAGE__->register_method(
1387 method => "user_transactions",
1388 api_name => "open-ils.actor.user.transactions.have_charge",
1389 notes => <<" NOTES");
1390 Returns a list of all open user transactions (mbts objects) that have an initial charge
1391 Params are login_session, user_id
1392 Optional third parameter is the transactions type. defaults to all
1395 __PACKAGE__->register_method(
1396 method => "user_transactions",
1397 api_name => "open-ils.actor.user.transactions.have_balance",
1398 notes => <<" NOTES");
1399 Returns a list of all open user transactions (mbts objects) that have a balance
1400 Params are login_session, user_id
1401 Optional third parameter is the transactions type. defaults to all
1404 __PACKAGE__->register_method(
1405 method => "user_transactions",
1406 api_name => "open-ils.actor.user.transactions.fleshed",
1407 notes => <<" NOTES");
1408 Returns an object/hash of transaction, circ, title where transaction = an open
1409 user transactions (mbts objects), circ is the attached circluation, and title
1410 is the title the circ points to
1411 Params are login_session, user_id
1412 Optional third parameter is the transactions type. defaults to all
1415 __PACKAGE__->register_method(
1416 method => "user_transactions",
1417 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1418 notes => <<" NOTES");
1419 Returns an object/hash of transaction, circ, title where transaction = an open
1420 user transactions that has an initial charge (mbts objects), circ is the
1421 attached circluation, and title is the title the circ points to
1422 Params are login_session, user_id
1423 Optional third parameter is the transactions type. defaults to all
1426 __PACKAGE__->register_method(
1427 method => "user_transactions",
1428 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1429 notes => <<" NOTES");
1430 Returns an object/hash of transaction, circ, title where transaction = an open
1431 user transaction that has a balance (mbts objects), circ is the attached
1432 circluation, and title is the title the circ points to
1433 Params are login_session, user_id
1434 Optional third parameter is the transaction type. defaults to all
1437 __PACKAGE__->register_method(
1438 method => "user_transactions",
1439 api_name => "open-ils.actor.user.transactions.count",
1440 notes => <<" NOTES");
1441 Returns an object/hash of transaction, circ, title where transaction = an open
1442 user transactions (mbts objects), circ is the attached circluation, and title
1443 is the title the circ points to
1444 Params are login_session, user_id
1445 Optional third parameter is the transactions type. defaults to all
1448 __PACKAGE__->register_method(
1449 method => "user_transactions",
1450 api_name => "open-ils.actor.user.transactions.have_charge.count",
1451 notes => <<" NOTES");
1452 Returns an object/hash of transaction, circ, title where transaction = an open
1453 user transactions that has an initial charge (mbts objects), circ is the
1454 attached circluation, and title is the title the circ points to
1455 Params are login_session, user_id
1456 Optional third parameter is the transactions type. defaults to all
1459 __PACKAGE__->register_method(
1460 method => "user_transactions",
1461 api_name => "open-ils.actor.user.transactions.have_balance.count",
1462 notes => <<" NOTES");
1463 Returns an object/hash of transaction, circ, title where transaction = an open
1464 user transaction that has a balance (mbts objects), circ is the attached
1465 circluation, and title is the title the circ points to
1466 Params are login_session, user_id
1467 Optional third parameter is the transaction type. defaults to all
1470 __PACKAGE__->register_method(
1471 method => "user_transactions",
1472 api_name => "open-ils.actor.user.transactions.have_balance.total",
1473 notes => <<" NOTES");
1474 Returns an object/hash of transaction, circ, title where transaction = an open
1475 user transaction that has a balance (mbts objects), circ is the attached
1476 circluation, and title is the title the circ points to
1477 Params are login_session, user_id
1478 Optional third parameter is the transaction type. defaults to all
1483 sub user_transactions {
1484 my( $self, $client, $login_session, $user_id, $type ) = @_;
1486 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1487 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1488 return $evt if $evt;
1490 my $api = $self->api_name();
1494 if(defined($type)) { @xact = (xact_type => $type);
1496 } else { @xact = (); }
1499 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1500 ->run($login_session => $user_id => $type);
1502 if($api =~ /have_charge/o) {
1504 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1506 } elsif($api =~ /have_balance/o) {
1508 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1511 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1515 if($api =~ /total/o) {
1517 for my $t (@$trans) {
1518 $total += $t->balance_owed;
1521 $logger->debug("Total balance owed by user $user_id: $total");
1525 if($api =~ /count/o) { return scalar @$trans; }
1526 if($api !~ /fleshed/o) { return $trans; }
1529 for my $t (@$trans) {
1531 if( $t->xact_type ne 'circulation' ) {
1532 push @resp, {transaction => $t};
1536 my $circ = $apputils->simple_scalar_request(
1538 "open-ils.cstore.direct.action.circulation.retrieve",
1543 my $title = $apputils->simple_scalar_request(
1545 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1546 $circ->target_copy );
1550 my $u = OpenILS::Utils::ModsParser->new();
1551 $u->start_mods_batch($title->marc());
1552 my $mods = $u->finish_mods_batch();
1553 $mods->doc_id($title->id) if $mods;
1555 push @resp, {transaction => $t, circ => $circ, record => $mods };
1563 __PACKAGE__->register_method(
1564 method => "user_transaction_retrieve",
1565 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1567 notes => <<" NOTES");
1568 Returns a fleshedtransaction record
1570 __PACKAGE__->register_method(
1571 method => "user_transaction_retrieve",
1572 api_name => "open-ils.actor.user.transaction.retrieve",
1574 notes => <<" NOTES");
1575 Returns a transaction record
1577 sub user_transaction_retrieve {
1578 my( $self, $client, $login_session, $bill_id ) = @_;
1580 # XXX I think I'm deprecated... make sure
1582 my $trans = $apputils->simple_scalar_request(
1584 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1588 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1589 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1590 return $evt if $evt;
1592 my $api = $self->api_name();
1593 if($api !~ /fleshed/o) { return $trans; }
1595 if( $trans->xact_type ne 'circulation' ) {
1596 $logger->debug("Returning non-circ transaction");
1597 return {transaction => $trans};
1600 my $circ = $apputils->simple_scalar_request(
1602 "open-ils..direct.action.circulation.retrieve",
1605 return {transaction => $trans} unless $circ;
1606 $logger->debug("Found the circ transaction");
1608 my $title = $apputils->simple_scalar_request(
1610 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1611 $circ->target_copy );
1613 return {transaction => $trans, circ => $circ } unless $title;
1614 $logger->debug("Found the circ title");
1618 my $u = OpenILS::Utils::ModsParser->new();
1619 $u->start_mods_batch($title->marc());
1620 $mods = $u->finish_mods_batch();
1622 if ($title->id == OILS_PRECAT_RECORD) {
1623 my $copy = $apputils->simple_scalar_request(
1625 "open-ils.cstore.direct.asset.copy.retrieve",
1626 $circ->target_copy );
1628 $mods = new Fieldmapper::metabib::virtual_record;
1629 $mods->doc_id(OILS_PRECAT_RECORD);
1630 $mods->title($copy->dummy_title);
1631 $mods->author($copy->dummy_author);
1635 $logger->debug("MODSized the circ title");
1637 return {transaction => $trans, circ => $circ, record => $mods };
1641 __PACKAGE__->register_method(
1642 method => "hold_request_count",
1643 api_name => "open-ils.actor.user.hold_requests.count",
1646 notes => <<" NOTES");
1647 Returns hold ready/total counts
1649 sub hold_request_count {
1650 my( $self, $client, $login_session, $userid ) = @_;
1652 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1653 $login_session, $userid, 'VIEW_HOLD' );
1654 return $evt if $evt;
1657 my $holds = $apputils->simple_scalar_request(
1659 "open-ils.cstore.direct.action.hold_request.search.atomic",
1662 fulfillment_time => {"=" => undef },
1663 cancel_time => undef,
1668 for my $h (@$holds) {
1669 next unless $h->capture_time and $h->current_copy;
1671 my $copy = $apputils->simple_scalar_request(
1673 "open-ils.cstore.direct.asset.copy.retrieve",
1677 if ($copy and $copy->status == 8) {
1682 return { total => scalar(@$holds), ready => scalar(@ready) };
1686 __PACKAGE__->register_method(
1687 method => "checkedout_count",
1688 api_name => "open-ils.actor.user.checked_out.count__",
1690 notes => <<" NOTES");
1691 Returns a transaction record
1695 sub checkedout_count {
1696 my( $self, $client, $login_session, $userid ) = @_;
1698 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1699 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1700 return $evt if $evt;
1702 my $circs = $apputils->simple_scalar_request(
1704 "open-ils.cstore.direct.action.circulation.search.atomic",
1705 { usr => $userid, stop_fines => undef }
1706 #{ usr => $userid, checkin_time => {"=" => undef } }
1709 my $parser = DateTime::Format::ISO8601->new;
1712 for my $c (@$circs) {
1713 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1714 my $due = $due_dt->epoch;
1716 if ($due < DateTime->today->epoch) {
1721 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1725 __PACKAGE__->register_method(
1726 method => "checked_out",
1727 api_name => "open-ils.actor.user.checked_out",
1731 Returns a structure of circulations objects sorted by
1732 out, overdue, lost, claims_returned, long_overdue.
1733 A list of IDs are returned of each type.
1734 lost, long_overdue, and claims_returned circ will not
1735 be "finished" (there is an outstanding balance or some
1736 other pending action on the circ).
1738 The .count method also includes a 'total' field which
1739 sums all "open" circs
1743 __PACKAGE__->register_method(
1744 method => "checked_out",
1745 api_name => "open-ils.actor.user.checked_out.count",
1748 signature => q/@see open-ils.actor.user.checked_out/
1752 my( $self, $conn, $auth, $userid ) = @_;
1754 my $e = new_editor(authtoken=>$auth);
1755 return $e->event unless $e->checkauth;
1757 if( $userid ne $e->requestor->id ) {
1758 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1761 my $count = $self->api_name =~ /count/;
1762 return _checked_out( $count, $e, $userid );
1766 my( $iscount, $e, $userid ) = @_;
1769 my $meth = 'open-ils.storage.actor.user.checked_out';
1770 $meth = "$meth.count" if $iscount;
1771 return $U->storagereq($meth, $userid);
1773 # XXX Old code - moved to storage
1774 #------------------------------------------------------------------------------
1775 #------------------------------------------------------------------------------
1776 my $circs = $e->search_action_circulation(
1777 { usr => $userid, checkin_time => undef });
1779 my $parser = DateTime::Format::ISO8601->new;
1781 # split the circs up into overdue and not-overdue circs
1783 for my $c (@$circs) {
1784 if( $c->due_date ) {
1785 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1786 my $due = $due_dt->epoch;
1787 if ($due < DateTime->today->epoch) {
1797 my( @open, @od, @lost, @cr, @lo );
1799 while (my $c = shift(@out)) {
1800 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1801 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1802 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1803 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1806 while (my $c = shift(@overdue)) {
1807 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1808 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1809 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1810 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1815 total => @open + @od + @lost + @cr + @lo,
1816 out => scalar(@open),
1817 overdue => scalar(@od),
1818 lost => scalar(@lost),
1819 claims_returned => scalar(@cr),
1820 long_overdue => scalar(@lo)
1828 claims_returned => \@cr,
1829 long_overdue => \@lo
1834 sub _checked_out_WHAT {
1835 my( $iscount, $e, $userid ) = @_;
1837 my $circs = $e->search_action_circulation(
1838 { usr => $userid, stop_fines => undef });
1840 my $mcircs = $e->search_action_circulation(
1843 checkin_time => undef,
1844 xact_finish => undef,
1848 push( @$circs, @$mcircs );
1850 my $parser = DateTime::Format::ISO8601->new;
1852 # split the circs up into overdue and not-overdue circs
1854 for my $c (@$circs) {
1855 if( $c->due_date ) {
1856 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1857 my $due = $due_dt->epoch;
1858 if ($due < DateTime->today->epoch) {
1859 push @overdue, $c->id;
1868 # grab all of the lost, claims-returned, and longoverdue circs
1869 #my $open = $e->search_action_circulation(
1870 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1873 # these items have stop_fines, but no xact_finish, so money
1874 # is owed on them and they have not been checked in
1875 my $open = $e->search_action_circulation(
1878 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1879 xact_finish => undef,
1880 checkin_time => undef,
1885 my( @lost, @cr, @lo );
1886 for my $c (@$open) {
1887 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1888 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1889 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1895 total => @$circs + @lost + @cr + @lo,
1896 out => scalar(@out),
1897 overdue => scalar(@overdue),
1898 lost => scalar(@lost),
1899 claims_returned => scalar(@cr),
1900 long_overdue => scalar(@lo)
1906 overdue => \@overdue,
1908 claims_returned => \@cr,
1909 long_overdue => \@lo
1915 __PACKAGE__->register_method(
1916 method => "checked_in_with_fines",
1917 api_name => "open-ils.actor.user.checked_in_with_fines",
1920 signature => q/@see open-ils.actor.user.checked_out/
1922 sub checked_in_with_fines {
1923 my( $self, $conn, $auth, $userid ) = @_;
1925 my $e = new_editor(authtoken=>$auth);
1926 return $e->event unless $e->checkauth;
1928 if( $userid ne $e->requestor->id ) {
1929 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1932 # money is owed on these items and they are checked in
1933 my $open = $e->search_action_circulation(
1936 xact_finish => undef,
1937 checkin_time => { "!=" => undef },
1942 my( @lost, @cr, @lo );
1943 for my $c (@$open) {
1944 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1945 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1946 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1951 claims_returned => \@cr,
1952 long_overdue => \@lo
1964 __PACKAGE__->register_method(
1965 method => "user_transaction_history",
1966 api_name => "open-ils.actor.user.transactions.history",
1968 notes => <<" NOTES");
1969 Returns a list of billable transaction ids for a user, optionally by type
1971 __PACKAGE__->register_method(
1972 method => "user_transaction_history",
1973 api_name => "open-ils.actor.user.transactions.history.have_charge",
1975 notes => <<" NOTES");
1976 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1978 __PACKAGE__->register_method(
1979 method => "user_transaction_history",
1980 api_name => "open-ils.actor.user.transactions.history.have_balance",
1983 notes => <<" NOTES");
1984 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1986 __PACKAGE__->register_method(
1987 method => "user_transaction_history",
1988 api_name => "open-ils.actor.user.transactions.history.still_open",
1990 notes => <<" NOTES");
1991 Returns a list of billable transaction ids for a user that are not finished
1993 __PACKAGE__->register_method(
1994 method => "user_transaction_history",
1995 api_name => "open-ils.actor.user.transactions.history.have_bill",
1998 notes => <<" NOTES");
1999 Returns a list of billable transaction ids for a user that has billings
2005 sub _user_transaction_history {
2006 my( $self, $client, $login_session, $user_id, $type ) = @_;
2008 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2009 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2010 return $evt if $evt;
2012 my $api = $self->api_name();
2017 @xact = (xact_type => $type) if(defined($type));
2018 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2019 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2021 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2023 my $trans = $apputils->simple_scalar_request(
2025 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2026 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2028 return [ map { $_->id } @$trans ];
2032 =head SEE APPUTILS.PM
2037 for my $x (@xacts) {
2038 my $s = new Fieldmapper::money::billable_transaction_summary;
2041 $s->xact_start( $x->xact_start );
2042 $s->xact_finish( $x->xact_finish );
2046 for my $b (@{ $x->billings }) {
2047 next if ($U->is_true($b->voided));
2048 $to += ($b->amount * 100);
2049 $lb ||= $b->billing_ts;
2050 if ($b->billing_ts ge $lb) {
2051 $lb = $b->billing_ts;
2052 $s->last_billing_note($b->note);
2053 $s->last_billing_ts($b->billing_ts);
2054 $s->last_billing_type($b->billing_type);
2058 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2062 for my $p (@{ $x->payments }) {
2063 next if ($U->is_true($p->voided));
2064 $tp += ($p->amount * 100);
2065 $lp ||= $p->payment_ts;
2066 if ($p->payment_ts ge $lp) {
2067 $lp = $p->payment_ts;
2068 $s->last_payment_note($p->note);
2069 $s->last_payment_ts($p->payment_ts);
2070 $s->last_payment_type($p->payment_type);
2073 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2075 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2077 $s->xact_type( 'grocery' ) if ($x->grocery);
2078 $s->xact_type( 'circulation' ) if ($x->circulation);
2087 sub user_transaction_history {
2088 my( $self, $conn, $auth, $userid, $type ) = @_;
2090 # run inside of a transaction to prevent replication delays
2091 my $e = new_editor(xact=>1, authtoken=>$auth);
2092 return $e->die_event unless $e->checkauth;
2094 if( $e->requestor->id ne $userid ) {
2095 return $e->die_event
2096 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2099 my $api = $self->api_name;
2100 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2102 my @xacts = @{ $e->search_money_billable_transaction(
2103 [ { usr => $userid, @xact_finish },
2105 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2106 order_by => { mbt => 'xact_start DESC' },
2114 #my @mbts = _make_mbts( @xacts );
2115 my @mbts = $U->make_mbts( @xacts );
2117 if(defined($type)) {
2118 @mbts = grep { $_->xact_type eq $type } @mbts;
2121 if($api =~ /have_balance/o) {
2122 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2125 if($api =~ /have_charge/o) {
2126 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2129 if($api =~ /have_bill/o) {
2130 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2138 __PACKAGE__->register_method(
2139 method => "user_perms",
2140 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2142 notes => <<" NOTES");
2143 Returns a list of permissions
2146 my( $self, $client, $authtoken, $user ) = @_;
2148 my( $staff, $evt ) = $apputils->checkses($authtoken);
2149 return $evt if $evt;
2151 $user ||= $staff->id;
2153 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2157 return $apputils->simple_scalar_request(
2159 "open-ils.storage.permission.user_perms.atomic",
2163 __PACKAGE__->register_method(
2164 method => "retrieve_perms",
2165 api_name => "open-ils.actor.permissions.retrieve",
2166 notes => <<" NOTES");
2167 Returns a list of permissions
2169 sub retrieve_perms {
2170 my( $self, $client ) = @_;
2171 return $apputils->simple_scalar_request(
2173 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2174 { id => { '!=' => undef } }
2178 __PACKAGE__->register_method(
2179 method => "retrieve_groups",
2180 api_name => "open-ils.actor.groups.retrieve",
2181 notes => <<" NOTES");
2182 Returns a list of user groupss
2184 sub retrieve_groups {
2185 my( $self, $client ) = @_;
2186 return new_editor()->retrieve_all_permission_grp_tree();
2189 __PACKAGE__->register_method(
2190 method => "retrieve_org_address",
2191 api_name => "open-ils.actor.org_unit.address.retrieve",
2192 notes => <<' NOTES');
2193 Returns an org_unit address by ID
2194 @param An org_address ID
2196 sub retrieve_org_address {
2197 my( $self, $client, $id ) = @_;
2198 return $apputils->simple_scalar_request(
2200 "open-ils.cstore.direct.actor.org_address.retrieve",
2205 __PACKAGE__->register_method(
2206 method => "retrieve_groups_tree",
2207 api_name => "open-ils.actor.groups.tree.retrieve",
2208 notes => <<" NOTES");
2209 Returns a list of user groups
2211 sub retrieve_groups_tree {
2212 my( $self, $client ) = @_;
2213 return new_editor()->search_permission_grp_tree(
2218 flesh_fields => { pgt => ["children"] },
2219 order_by => { pgt => 'name'}
2226 # turns an org list into an org tree
2228 sub build_group_tree {
2230 my( $self, $grplist) = @_;
2232 return $grplist unless (
2233 ref($grplist) and @$grplist > 1 );
2235 my @list = sort { $a->name cmp $b->name } @$grplist;
2238 for my $grp (@list) {
2240 if ($grp and !defined($grp->parent)) {
2244 my ($parent) = grep { $_->id == $grp->parent} @list;
2246 $parent->children([]) unless defined($parent->children);
2247 push( @{$parent->children}, $grp );
2255 __PACKAGE__->register_method(
2256 method => "add_user_to_groups",
2257 api_name => "open-ils.actor.user.set_groups",
2258 notes => <<" NOTES");
2259 Adds a user to one or more permission groups
2262 sub add_user_to_groups {
2263 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2265 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2266 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2267 return $evt if $evt;
2269 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2270 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2271 return $evt if $evt;
2273 $apputils->simplereq(
2275 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2277 for my $group (@$groups) {
2278 my $link = Fieldmapper::permission::usr_grp_map->new;
2280 $link->usr($userid);
2282 my $id = $apputils->simplereq(
2284 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2290 __PACKAGE__->register_method(
2291 method => "get_user_perm_groups",
2292 api_name => "open-ils.actor.user.get_groups",
2293 notes => <<" NOTES");
2294 Retrieve a user's permission groups.
2298 sub get_user_perm_groups {
2299 my( $self, $client, $authtoken, $userid ) = @_;
2301 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2302 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2303 return $evt if $evt;
2305 return $apputils->simplereq(
2307 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2311 __PACKAGE__->register_method(
2312 method => "get_user_work_ous",
2313 api_name => "open-ils.actor.user.get_work_ous",
2314 notes => <<" NOTES");
2315 Retrieve a user's work org units.
2317 __PACKAGE__->register_method(
2318 method => "get_user_work_ous",
2319 api_name => "open-ils.actor.user.get_work_ous.ids",
2320 notes => <<" NOTES");
2321 Retrieve a user's work org units.
2325 sub get_user_work_ous {
2326 my( $self, $client, $auth, $userid ) = @_;
2327 my $e = new_editor(authtoken=>$auth);
2328 return $e->event unless $e->checkauth;
2329 $userid ||= $e->requestor->id;
2331 if($e->requestor->id != $userid) {
2332 my $user = $e->retrieve_actor_user($userid)
2333 or return $e->event;
2334 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2337 return $e->search_permission_usr_work_ou_map({usr => $userid})
2338 unless $self->api_name =~ /.ids$/;
2340 # client just wants a list of org IDs
2341 return $U->get_user_work_ou_ids($e, $userid);
2347 __PACKAGE__->register_method (
2348 method => 'register_workstation',
2349 api_name => 'open-ils.actor.workstation.register.override',
2350 signature => q/@see open-ils.actor.workstation.register/);
2352 __PACKAGE__->register_method (
2353 method => 'register_workstation',
2354 api_name => 'open-ils.actor.workstation.register',
2356 Registers a new workstion in the system
2357 @param authtoken The login session key
2358 @param name The name of the workstation id
2359 @param owner The org unit that owns this workstation
2360 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2361 if the name is already in use.
2364 sub register_workstation {
2365 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2367 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2368 return $e->die_event unless $e->checkauth;
2369 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2370 my $existing = $e->search_actor_workstation({name => $name})->[0];
2374 if( $self->api_name =~ /override/o ) {
2375 # workstation with the given name exists.
2377 if($owner ne $existing->owning_lib) {
2378 # if necessary, update the owning_lib of the workstation
2380 $logger->info("changing owning lib of workstation ".$existing->id.
2381 " from ".$existing->owning_lib." to $owner");
2382 return $e->die_event unless
2383 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2385 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2387 $existing->owning_lib($owner);
2388 return $e->die_event unless $e->update_actor_workstation($existing);
2394 "attempt to register an existing workstation. returning existing ID");
2397 return $existing->id;
2400 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2404 my $ws = Fieldmapper::actor::workstation->new;
2405 $ws->owning_lib($owner);
2407 $e->create_actor_workstation($ws) or return $e->die_event;
2409 return $ws->id; # note: editor sets the id on the new object for us
2412 __PACKAGE__->register_method (
2413 method => 'workstation_list',
2414 api_name => 'open-ils.actor.workstation.list',
2416 Returns a list of workstations registered at the given location
2417 @param authtoken The login session key
2418 @param ids A list of org_unit.id's for the workstation owners
2421 sub workstation_list {
2422 my( $self, $conn, $authtoken, @orgs ) = @_;
2424 my $e = new_editor(authtoken=>$authtoken);
2425 return $e->event unless $e->checkauth;
2430 unless $e->allowed('REGISTER_WORKSTATION', $o);
2431 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2442 __PACKAGE__->register_method (
2443 method => 'fetch_patron_note',
2444 api_name => 'open-ils.actor.note.retrieve.all',
2447 Returns a list of notes for a given user
2448 Requestor must have VIEW_USER permission if pub==false and
2449 @param authtoken The login session key
2450 @param args Hash of params including
2451 patronid : the patron's id
2452 pub : true if retrieving only public notes
2456 sub fetch_patron_note {
2457 my( $self, $conn, $authtoken, $args ) = @_;
2458 my $patronid = $$args{patronid};
2460 my($reqr, $evt) = $U->checkses($authtoken);
2461 return $evt if $evt;
2464 ($patron, $evt) = $U->fetch_user($patronid);
2465 return $evt if $evt;
2468 if( $patronid ne $reqr->id ) {
2469 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2470 return $evt if $evt;
2472 return $U->cstorereq(
2473 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2474 { usr => $patronid, pub => 't' } );
2477 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2478 return $evt if $evt;
2480 return $U->cstorereq(
2481 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2484 __PACKAGE__->register_method (
2485 method => 'create_user_note',
2486 api_name => 'open-ils.actor.note.create',
2488 Creates a new note for the given user
2489 @param authtoken The login session key
2490 @param note The note object
2493 sub create_user_note {
2494 my( $self, $conn, $authtoken, $note ) = @_;
2495 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2496 return $e->die_event unless $e->checkauth;
2498 my $user = $e->retrieve_actor_user($note->usr)
2499 or return $e->die_event;
2501 return $e->die_event unless
2502 $e->allowed('UPDATE_USER',$user->home_ou);
2504 $note->creator($e->requestor->id);
2505 $e->create_actor_usr_note($note) or return $e->die_event;
2511 __PACKAGE__->register_method (
2512 method => 'delete_user_note',
2513 api_name => 'open-ils.actor.note.delete',
2515 Deletes a note for the given user
2516 @param authtoken The login session key
2517 @param noteid The note id
2520 sub delete_user_note {
2521 my( $self, $conn, $authtoken, $noteid ) = @_;
2523 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2524 return $e->die_event unless $e->checkauth;
2525 my $note = $e->retrieve_actor_usr_note($noteid)
2526 or return $e->die_event;
2527 my $user = $e->retrieve_actor_user($note->usr)
2528 or return $e->die_event;
2529 return $e->die_event unless
2530 $e->allowed('UPDATE_USER', $user->home_ou);
2532 $e->delete_actor_usr_note($note) or return $e->die_event;
2538 __PACKAGE__->register_method (
2539 method => 'update_user_note',
2540 api_name => 'open-ils.actor.note.update',
2542 @param authtoken The login session key
2543 @param note The note
2547 sub update_user_note {
2548 my( $self, $conn, $auth, $note ) = @_;
2549 my $e = new_editor(authtoken=>$auth, xact=>1);
2550 return $e->event unless $e->checkauth;
2551 my $patron = $e->retrieve_actor_user($note->usr)
2552 or return $e->event;
2553 return $e->event unless
2554 $e->allowed('UPDATE_USER', $patron->home_ou);
2555 $e->update_actor_user_note($note)
2556 or return $e->event;
2564 __PACKAGE__->register_method (
2565 method => 'create_closed_date',
2566 api_name => 'open-ils.actor.org_unit.closed_date.create',
2568 Creates a new closing entry for the given org_unit
2569 @param authtoken The login session key
2570 @param note The closed_date object
2573 sub create_closed_date {
2574 my( $self, $conn, $authtoken, $cd ) = @_;
2576 my( $user, $evt ) = $U->checkses($authtoken);
2577 return $evt if $evt;
2579 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2580 return $evt if $evt;
2582 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2584 my $id = $U->storagereq(
2585 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2586 return $U->DB_UPDATE_FAILED($cd) unless $id;
2591 __PACKAGE__->register_method (
2592 method => 'delete_closed_date',
2593 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2595 Deletes a closing entry for the given org_unit
2596 @param authtoken The login session key
2597 @param noteid The close_date id
2600 sub delete_closed_date {
2601 my( $self, $conn, $authtoken, $cd ) = @_;
2603 my( $user, $evt ) = $U->checkses($authtoken);
2604 return $evt if $evt;
2607 ($cd_obj, $evt) = fetch_closed_date($cd);
2608 return $evt if $evt;
2610 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2611 return $evt if $evt;
2613 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2615 my $stat = $U->storagereq(
2616 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2617 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2622 __PACKAGE__->register_method(
2623 method => 'usrname_exists',
2624 api_name => 'open-ils.actor.username.exists',
2626 Returns 1 if the requested username exists, returns 0 otherwise
2630 sub usrname_exists {
2631 my( $self, $conn, $auth, $usrname ) = @_;
2632 my $e = new_editor(authtoken=>$auth);
2633 return $e->event unless $e->checkauth;
2634 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2635 return $$a[0] if $a and @$a;
2639 __PACKAGE__->register_method(
2640 method => 'barcode_exists',
2641 api_name => 'open-ils.actor.barcode.exists',
2644 Returns 1 if the requested barcode exists, returns 0 otherwise
2648 sub barcode_exists {
2649 my( $self, $conn, $auth, $barcode ) = @_;
2650 my $e = new_editor(authtoken=>$auth);
2651 return $e->event unless $e->checkauth;
2652 my $card = $e->search_actor_card({barcode => $barcode});
2653 return undef unless @$card;
2654 return $card->[0]->usr;
2658 __PACKAGE__->register_method(
2659 method => 'retrieve_net_levels',
2660 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2663 sub retrieve_net_levels {
2664 my( $self, $conn, $auth ) = @_;
2665 my $e = new_editor(authtoken=>$auth);
2666 return $e->event unless $e->checkauth;
2667 return $e->retrieve_all_config_net_access_level();
2671 __PACKAGE__->register_method(
2672 method => 'fetch_org_by_shortname',
2673 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2675 sub fetch_org_by_shortname {
2676 my( $self, $conn, $sname ) = @_;
2677 my $e = new_editor();
2678 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2679 return $e->event unless $org;
2684 __PACKAGE__->register_method(
2685 method => 'session_home_lib',
2686 api_name => 'open-ils.actor.session.home_lib',
2689 sub session_home_lib {
2690 my( $self, $conn, $auth ) = @_;
2691 my $e = new_editor(authtoken=>$auth);
2692 return undef unless $e->checkauth;
2693 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2694 return $org->shortname;
2697 __PACKAGE__->register_method(
2698 method => 'session_safe_token',
2699 api_name => 'open-ils.actor.session.safe_token',
2701 Returns a hashed session ID that is safe for export to the world.
2702 This safe token will expire after 1 hour of non-use.
2703 @param auth Active authentication token
2707 sub session_safe_token {
2708 my( $self, $conn, $auth ) = @_;
2709 my $e = new_editor(authtoken=>$auth);
2710 return undef unless $e->checkauth;
2712 my $safe_token = md5_hex($auth);
2714 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2716 # Add more like the following if needed...
2718 "safe-token-home_lib-shortname-$safe_token",
2719 $e->retrieve_actor_org_unit(
2720 $e->requestor->home_ou
2729 __PACKAGE__->register_method(
2730 method => 'safe_token_home_lib',
2731 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2733 Returns the home library shortname from the session
2734 asscociated with a safe token from generated by
2735 open-ils.actor.session.safe_token.
2736 @param safe_token Active safe token
2740 sub safe_token_home_lib {
2741 my( $self, $conn, $safe_token ) = @_;
2743 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2744 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2749 __PACKAGE__->register_method(
2750 method => 'slim_tree',
2751 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2754 my $tree = new_editor()->search_actor_org_unit(
2756 {"parent_ou" => undef },
2759 flesh_fields => { aou => ['children'] },
2760 order_by => { aou => 'name'},
2761 select => { aou => ["id","shortname", "name"]},
2766 return trim_tree($tree);
2772 return undef unless $tree;
2774 code => $tree->shortname,
2775 name => $tree->name,
2777 if( $tree->children and @{$tree->children} ) {
2778 $htree->{children} = [];
2779 for my $c (@{$tree->children}) {
2780 push( @{$htree->{children}}, trim_tree($c) );
2788 __PACKAGE__->register_method(
2789 method => "update_penalties",
2790 api_name => "open-ils.actor.user.penalties.update");
2791 sub update_penalties {
2792 my( $self, $conn, $auth, $userid ) = @_;
2793 my $e = new_editor(authtoken=>$auth);
2794 return $e->event unless $e->checkauth;
2795 $U->update_patron_penalties(
2797 patronid => $userid,
2804 __PACKAGE__->register_method(
2805 method => "user_retrieve_fleshed_by_id",
2806 api_name => "open-ils.actor.user.fleshed.retrieve",);
2808 sub user_retrieve_fleshed_by_id {
2809 my( $self, $client, $auth, $user_id, $fields ) = @_;
2810 my $e = new_editor(authtoken => $auth);
2811 return $e->event unless $e->checkauth;
2813 if( $e->requestor->id != $user_id ) {
2814 return $e->event unless $e->allowed('VIEW_USER');
2820 "standing_penalties",
2824 "stat_cat_entries" ];
2825 return new_flesh_user($user_id, $fields, $e);
2829 sub new_flesh_user {
2832 my $fields = shift || [];
2833 my $e = shift || new_editor(xact=>1);
2835 my $user = $e->retrieve_actor_user(
2840 "flesh_fields" => { "au" => $fields }
2843 ) or return $e->event;
2846 if( grep { $_ eq 'addresses' } @$fields ) {
2848 $user->addresses([]) unless @{$user->addresses};
2850 if( ref $user->billing_address ) {
2851 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2852 push( @{$user->addresses}, $user->billing_address );
2856 if( ref $user->mailing_address ) {
2857 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2858 push( @{$user->addresses}, $user->mailing_address );
2864 $user->clear_passwd();
2871 __PACKAGE__->register_method(
2872 method => "user_retrieve_parts",
2873 api_name => "open-ils.actor.user.retrieve.parts",);
2875 sub user_retrieve_parts {
2876 my( $self, $client, $auth, $user_id, $fields ) = @_;
2877 my $e = new_editor(authtoken => $auth);
2878 return $e->event unless $e->checkauth;
2879 if( $e->requestor->id != $user_id ) {
2880 return $e->event unless $e->allowed('VIEW_USER');
2883 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2884 push(@resp, $user->$_()) for(@$fields);
2890 __PACKAGE__->register_method(
2891 method => 'user_opt_in_enabled',
2892 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2894 @return 1 if user opt-in is globally enabled, 0 otherwise.
2897 sub user_opt_in_enabled {
2898 my($self, $conn) = @_;
2899 my $sc = OpenSRF::Utils::SettingsClient->new;
2900 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2905 __PACKAGE__->register_method(
2906 method => 'user_opt_in_at_org',
2907 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2909 @param $auth The auth token
2910 @param user_id The ID of the user to test
2911 @return 1 if the user has opted in at the specified org,
2912 event on error, and 0 otherwise. /);
2913 sub user_opt_in_at_org {
2914 my($self, $conn, $auth, $user_id) = @_;
2916 # see if we even need to enforce the opt-in value
2917 return 1 unless user_opt_in_enabled($self);
2919 my $e = new_editor(authtoken => $auth);
2920 return $e->event unless $e->checkauth;
2921 my $org_id = $e->requestor->ws_ou;
2923 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2924 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2926 # user is automatically opted-in at the home org
2927 return 1 if $user->home_ou eq $org_id;
2929 my $vals = $e->search_actor_usr_org_unit_opt_in(
2930 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2936 __PACKAGE__->register_method(
2937 method => 'create_user_opt_in_at_org',
2938 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
2940 @param $auth The auth token
2941 @param user_id The ID of the user to test
2942 @return The ID of the newly created object, event on error./);
2944 sub create_user_opt_in_at_org {
2945 my($self, $conn, $auth, $user_id) = @_;
2947 my $e = new_editor(authtoken => $auth, xact=>1);
2948 return $e->die_event unless $e->checkauth;
2949 my $org_id = $e->requestor->ws_ou;
2951 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2952 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2954 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
2956 $opt_in->org_unit($org_id);
2957 $opt_in->usr($user_id);
2958 $opt_in->staff($e->requestor->id);
2959 $opt_in->opt_in_ts('now');
2960 $opt_in->opt_in_ws($e->requestor->wsid);
2962 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
2963 or return $e->die_event;