1 package OpenILS::Application::Actor;
2 use OpenILS::Application;
3 use base qw/OpenILS::Application/;
4 use strict; use warnings;
6 $Data::Dumper::Indent = 0;
9 use Digest::MD5 qw(md5_hex);
11 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::ModsParser;
18 use OpenSRF::Utils::Logger qw/$logger/;
19 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::SettingsClient;
22 use OpenSRF::Utils::Cache;
24 use OpenSRF::Utils::JSON;
26 use DateTime::Format::ISO8601;
27 use OpenILS::Const qw/:const/;
29 use OpenILS::Application::Actor::Container;
30 use OpenILS::Application::Actor::ClosedDates;
32 use OpenILS::Utils::CStoreEditor qw/:funcs/;
34 use OpenILS::Application::Actor::UserGroups;
36 OpenILS::Application::Actor::Container->initialize();
37 OpenILS::Application::Actor::UserGroups->initialize();
38 OpenILS::Application::Actor::ClosedDates->initialize();
41 my $apputils = "OpenILS::Application::AppUtils";
44 sub _d { warn "Patron:\n" . Dumper(shift()); }
49 my $set_user_settings;
52 __PACKAGE__->register_method(
53 method => "set_user_settings",
54 api_name => "open-ils.actor.patron.settings.update",
56 sub set_user_settings {
57 my( $self, $client, $user_session, $uid, $settings ) = @_;
59 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
61 my( $staff, $user, $evt ) =
62 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
66 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
68 $_->[1]->{value} = OpenSRF::Utils::JSON->perl2JSON($_->[1]->{value}) for @params;
70 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
72 my $ses = $U->start_db_session();
73 my $stat = $ses->request(
74 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
75 $U->commit_db_session($ses);
81 __PACKAGE__->register_method(
82 method => "set_ou_settings",
83 api_name => "open-ils.actor.org_unit.settings.update",
86 my( $self, $client, $auth, $org_id, $settings ) = @_;
88 my $e = new_editor(authtoken => $auth, xact => 1);
89 return $e->die_event unless $e->checkauth;
90 return $e->die_event unless $e->allowed('UPDATE_ORG_SETTING', $org_id);
92 for my $name (keys %$settings) {
93 my $val = $$settings{$name};
94 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
97 $val = OpenSRF::Utils::JSON->perl2JSON($val);
100 $e->update_actor_org_unit_setting($set) or return $e->die_event;
102 $set = Fieldmapper::actor::org_unit_setting->new;
103 $set->org_unit($org_id);
106 $e->create_actor_org_unit_setting($set) or return $e->die_event;
109 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
117 my $fetch_user_settings;
118 my $fetch_ou_settings;
120 __PACKAGE__->register_method(
121 method => "user_settings",
122 api_name => "open-ils.actor.patron.settings.retrieve",
125 my( $self, $client, $auth, $user_id, $setting ) = @_;
127 my $e = new_editor(authtoken => $auth);
128 return $e->event unless $e->checkauth;
130 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
131 if($e->requestor->id != $user_id) {
132 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
135 my $s = $e->search_actor_user_setting({usr => $user_id});
136 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
138 return $$settings{$setting} if $setting;
144 __PACKAGE__->register_method(
145 method => "ou_settings",
146 api_name => "open-ils.actor.org_unit.settings.retrieve",
149 my( $self, $client, $ouid ) = @_;
151 $logger->info("Fetching org unit settings for org $ouid");
153 my $s = $apputils->simplereq(
155 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
157 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
162 __PACKAGE__->register_method(
163 api_name => 'open-ils.actor.ou_setting.ancestor_default',
164 method => 'ou_ancestor_setting',
167 # ------------------------------------------------------------------
168 # Attempts to find the org setting value for a given org. if not
169 # found at the requested org, searches up the org tree until it
170 # finds a parent that has the requested setting.
171 # when found, returns { org => $id, value => $value }
172 # otherwise, returns NULL
173 # ------------------------------------------------------------------
174 sub ou_ancestor_setting {
175 my( $self, $client, $orgid, $name ) = @_;
176 return $U->ou_ancestor_setting($orgid, $name);
182 __PACKAGE__->register_method (
183 method => "ou_setting_delete",
184 api_name => 'open-ils.actor.org_setting.delete',
186 Deletes a specific org unit setting for a specific location
187 @param authtoken The login session key
188 @param orgid The org unit whose setting we're changing
189 @param setting The name of the setting to delete
190 @return True value on success.
194 sub ou_setting_delete {
195 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
196 my( $reqr, $evt) = $U->checkses($authtoken);
198 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
201 my $id = $U->cstorereq(
202 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
203 { name => $setting, org_unit => $orgid } );
205 $logger->debug("Retrieved setting $id in org unit setting delete");
207 my $s = $U->cstorereq(
208 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
210 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
224 __PACKAGE__->register_method(
225 method => "update_patron",
226 api_name => "open-ils.actor.patron.update",);
229 my( $self, $client, $user_session, $patron ) = @_;
231 my $session = $apputils->start_db_session();
235 $logger->info("Creating new patron...") if $patron->isnew;
236 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
238 my( $user_obj, $evt ) = $U->checkses($user_session);
241 $evt = check_group_perm($session, $user_obj, $patron);
245 # $new_patron is the patron in progress. $patron is the original patron
246 # passed in with the method. new_patron will change as the components
247 # of patron are added/updated.
251 # unflesh the real items on the patron
252 $patron->card( $patron->card->id ) if(ref($patron->card));
253 $patron->billing_address( $patron->billing_address->id )
254 if(ref($patron->billing_address));
255 $patron->mailing_address( $patron->mailing_address->id )
256 if(ref($patron->mailing_address));
258 # create/update the patron first so we can use his id
259 if($patron->isnew()) {
260 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
262 } else { $new_patron = $patron; }
264 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
267 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
270 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
273 # re-update the patron if anything has happened to him during this process
274 if($new_patron->ischanged()) {
275 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
279 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
282 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
285 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
288 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
291 if(!$patron->isnew) {
292 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
295 $apputils->commit_db_session($session);
296 my $fuser = flesh_user($new_patron->id());
299 # Log the new and old patron for investigation
300 $logger->info("$user_session updating patron object. orig patron object = ".
301 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
311 return new_flesh_user($id, [
314 "standing_penalties",
318 "stat_cat_entries" ] );
326 # clone and clear stuff that would break the database
330 my $new_patron = $patron->clone;
332 $new_patron->clear_billing_address();
333 $new_patron->clear_mailing_address();
334 $new_patron->clear_addresses();
335 $new_patron->clear_card();
336 $new_patron->clear_cards();
337 $new_patron->clear_id();
338 $new_patron->clear_isnew();
339 $new_patron->clear_ischanged();
340 $new_patron->clear_isdeleted();
341 $new_patron->clear_stat_cat_entries();
342 $new_patron->clear_permissions();
343 $new_patron->clear_standing_penalties();
353 my $user_obj = shift;
355 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
356 return (undef, $evt) if $evt;
358 my $ex = $session->request(
359 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
361 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
364 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
366 my $id = $session->request(
367 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
368 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
370 $logger->info("Successfully created new user [$id] in DB");
372 return ( $session->request(
373 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
377 sub check_group_perm {
378 my( $session, $requestor, $patron ) = @_;
381 # first let's see if the requestor has
382 # priveleges to update this user in any way
383 if( ! $patron->isnew ) {
384 my $p = $session->request(
385 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
387 # If we are the requestor (trying to update our own account)
388 # and we are not trying to change our profile, we're good
389 if( $p->id == $requestor->id and
390 $p->profile == $patron->profile ) {
395 $evt = group_perm_failed($session, $requestor, $p);
399 # They are allowed to edit this patron.. can they put the
400 # patron into the group requested?
401 $evt = group_perm_failed($session, $requestor, $patron);
407 sub group_perm_failed {
408 my( $session, $requestor, $patron ) = @_;
412 my $grpid = $patron->profile;
416 $logger->debug("user update looking for group perm for group $grpid");
417 $grp = $session->request(
418 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
419 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
421 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
423 $logger->info("user update checking perm $perm on user ".
424 $requestor->id." for update/create on user username=".$patron->usrname);
426 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
434 my( $session, $patron, $user_obj, $noperm) = @_;
436 $logger->info("Updating patron ".$patron->id." in DB");
441 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
442 return (undef, $evt) if $evt;
445 # update the password by itself to avoid the password protection magic
446 if( $patron->passwd ) {
447 my $s = $session->request(
448 'open-ils.storage.direct.actor.user.remote_update',
449 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
450 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
451 $patron->clear_passwd;
454 if(!$patron->ident_type) {
455 $patron->clear_ident_type;
456 $patron->clear_ident_value;
459 $evt = verify_last_xact($session, $patron);
460 return (undef, $evt) if $evt;
462 my $stat = $session->request(
463 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
464 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
469 sub verify_last_xact {
470 my( $session, $patron ) = @_;
471 return undef unless $patron->id and $patron->id > 0;
472 my $p = $session->request(
473 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
474 my $xact = $p->last_xact_id;
475 return undef unless $xact;
476 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
477 return OpenILS::Event->new('XACT_COLLISION')
478 if $xact != $patron->last_xact_id;
483 sub _check_dup_ident {
484 my( $session, $patron ) = @_;
486 return undef unless $patron->ident_value;
489 ident_type => $patron->ident_type,
490 ident_value => $patron->ident_value,
493 $logger->debug("patron update searching for dup ident values: " .
494 $patron->ident_type . ':' . $patron->ident_value);
496 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
498 my $dups = $session->request(
499 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
502 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
509 sub _add_update_addresses {
513 my $new_patron = shift;
517 my $current_id; # id of the address before creation
519 for my $address (@{$patron->addresses()}) {
521 next unless ref $address;
522 $current_id = $address->id();
524 if( $patron->billing_address() and
525 $patron->billing_address() == $current_id ) {
526 $logger->info("setting billing addr to $current_id");
527 $new_patron->billing_address($address->id());
528 $new_patron->ischanged(1);
531 if( $patron->mailing_address() and
532 $patron->mailing_address() == $current_id ) {
533 $new_patron->mailing_address($address->id());
534 $logger->info("setting mailing addr to $current_id");
535 $new_patron->ischanged(1);
539 if($address->isnew()) {
541 $address->usr($new_patron->id());
543 ($address, $evt) = _add_address($session,$address);
544 return (undef, $evt) if $evt;
546 # we need to get the new id
547 if( $patron->billing_address() and
548 $patron->billing_address() == $current_id ) {
549 $new_patron->billing_address($address->id());
550 $logger->info("setting billing addr to $current_id");
551 $new_patron->ischanged(1);
554 if( $patron->mailing_address() and
555 $patron->mailing_address() == $current_id ) {
556 $new_patron->mailing_address($address->id());
557 $logger->info("setting mailing addr to $current_id");
558 $new_patron->ischanged(1);
561 } elsif($address->ischanged() ) {
563 ($address, $evt) = _update_address($session, $address);
564 return (undef, $evt) if $evt;
566 } elsif($address->isdeleted() ) {
568 if( $address->id() == $new_patron->mailing_address() ) {
569 $new_patron->clear_mailing_address();
570 ($new_patron, $evt) = _update_patron($session, $new_patron);
571 return (undef, $evt) if $evt;
574 if( $address->id() == $new_patron->billing_address() ) {
575 $new_patron->clear_billing_address();
576 ($new_patron, $evt) = _update_patron($session, $new_patron);
577 return (undef, $evt) if $evt;
580 $evt = _delete_address($session, $address);
581 return (undef, $evt) if $evt;
585 return ( $new_patron, undef );
589 # adds an address to the db and returns the address with new id
591 my($session, $address) = @_;
592 $address->clear_id();
594 $logger->info("Creating new address at street ".$address->street1);
596 # put the address into the database
597 my $id = $session->request(
598 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
599 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
602 return ($address, undef);
606 sub _update_address {
607 my( $session, $address ) = @_;
609 $logger->info("Updating address ".$address->id." in the DB");
611 my $stat = $session->request(
612 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
614 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
615 return ($address, undef);
620 sub _add_update_cards {
624 my $new_patron = shift;
628 my $virtual_id; #id of the card before creation
629 for my $card (@{$patron->cards()}) {
631 $card->usr($new_patron->id());
633 if(ref($card) and $card->isnew()) {
635 $virtual_id = $card->id();
636 ( $card, $evt ) = _add_card($session,$card);
637 return (undef, $evt) if $evt;
639 #if(ref($patron->card)) { $patron->card($patron->card->id); }
640 if($patron->card() == $virtual_id) {
641 $new_patron->card($card->id());
642 $new_patron->ischanged(1);
645 } elsif( ref($card) and $card->ischanged() ) {
646 $evt = _update_card($session, $card);
647 return (undef, $evt) if $evt;
651 return ( $new_patron, undef );
655 # adds an card to the db and returns the card with new id
657 my( $session, $card ) = @_;
660 $logger->info("Adding new patron card ".$card->barcode);
662 my $id = $session->request(
663 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
664 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
665 $logger->info("Successfully created patron card $id");
668 return ( $card, undef );
672 # returns event on error. returns undef otherwise
674 my( $session, $card ) = @_;
675 $logger->info("Updating patron card ".$card->id);
677 my $stat = $session->request(
678 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
679 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
686 # returns event on error. returns undef otherwise
687 sub _delete_address {
688 my( $session, $address ) = @_;
690 $logger->info("Deleting address ".$address->id." from DB");
692 my $stat = $session->request(
693 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
695 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
701 sub _add_survey_responses {
702 my ($session, $patron, $new_patron) = @_;
704 $logger->info( "Updating survey responses for patron ".$new_patron->id );
706 my $responses = $patron->survey_responses;
710 $_->usr($new_patron->id) for (@$responses);
712 my $evt = $U->simplereq( "open-ils.circ",
713 "open-ils.circ.survey.submit.user_id", $responses );
715 return (undef, $evt) if defined($U->event_code($evt));
719 return ( $new_patron, undef );
723 sub _create_stat_maps {
725 my($session, $user_session, $patron, $new_patron) = @_;
727 my $maps = $patron->stat_cat_entries();
729 for my $map (@$maps) {
731 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
733 if ($map->isdeleted()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
736 } elsif ($map->isnew()) {
737 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
742 $map->target_usr($new_patron->id);
745 $logger->info("Updating stat entry with method $method and map $map");
747 my $stat = $session->request($method, $map)->gather(1);
748 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
752 return ($new_patron, undef);
755 sub _create_perm_maps {
757 my($session, $user_session, $patron, $new_patron) = @_;
759 my $maps = $patron->permissions;
761 for my $map (@$maps) {
763 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
764 if ($map->isdeleted()) {
765 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
766 } elsif ($map->isnew()) {
767 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
772 $map->usr($new_patron->id);
774 #warn( "Updating permissions with method $method and session $user_session and map $map" );
775 $logger->info( "Updating permissions with method $method and map $map" );
777 my $stat = $session->request($method, $map)->gather(1);
778 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
782 return ($new_patron, undef);
786 __PACKAGE__->register_method(
787 method => "set_user_work_ous",
788 api_name => "open-ils.actor.user.work_ous.update",
791 sub set_user_work_ous {
797 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
800 my $session = $apputils->start_db_session();
802 for my $map (@$maps) {
804 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
805 if ($map->isdeleted()) {
806 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
807 } elsif ($map->isnew()) {
808 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
812 #warn( "Updating permissions with method $method and session $ses and map $map" );
813 $logger->info( "Updating work_ou map with method $method and map $map" );
815 my $stat = $session->request($method, $map)->gather(1);
816 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
820 $apputils->commit_db_session($session);
822 return scalar(@$maps);
826 __PACKAGE__->register_method(
827 method => "set_user_perms",
828 api_name => "open-ils.actor.user.permissions.update",
837 my $session = $apputils->start_db_session();
839 my( $user_obj, $evt ) = $U->checkses($ses);
842 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
845 $all = 1 if ($user_obj->super_user());
846 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
848 for my $map (@$maps) {
850 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
851 if ($map->isdeleted()) {
852 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
853 } elsif ($map->isnew()) {
854 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
858 next if (!$all || !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
860 #warn( "Updating permissions with method $method and session $ses and map $map" );
861 $logger->info( "Updating permissions with method $method and map $map" );
863 my $stat = $session->request($method, $map)->gather(1);
864 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
868 $apputils->commit_db_session($session);
870 return scalar(@$maps);
874 sub _create_standing_penalties {
876 my($session, $user_session, $patron, $new_patron) = @_;
878 my $maps = $patron->standing_penalties;
881 for my $map (@$maps) {
883 if ($map->isdeleted()) {
884 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
885 } elsif ($map->isnew()) {
886 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
892 $map->usr($new_patron->id);
894 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
896 my $stat = $session->request($method, $map)->gather(1);
897 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
900 return ($new_patron, undef);
905 __PACKAGE__->register_method(
906 method => "search_username",
907 api_name => "open-ils.actor.user.search.username",
910 sub search_username {
911 my($self, $client, $username) = @_;
912 return new_editor()->search_actor_user({usrname=>$username});
918 __PACKAGE__->register_method(
919 method => "user_retrieve_by_barcode",
921 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
923 sub user_retrieve_by_barcode {
924 my($self, $client, $user_session, $barcode) = @_;
926 $logger->debug("Searching for user with barcode $barcode");
927 my ($user_obj, $evt) = $apputils->checkses($user_session);
930 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
932 "open-ils.cstore.direct.actor.card.search.atomic",
933 { barcode => $barcode }
936 if(!$card || !$card->[0]) {
937 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
941 my $user = flesh_user($card->usr());
943 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
946 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
953 __PACKAGE__->register_method(
954 method => "get_user_by_id",
955 api_name => "open-ils.actor.user.retrieve",);
958 my ($self, $client, $auth, $id) = @_;
959 my $e = new_editor(authtoken=>$auth);
960 return $e->event unless $e->checkauth;
961 my $user = $e->retrieve_actor_user($id)
963 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
969 __PACKAGE__->register_method(
970 method => "get_org_types",
971 api_name => "open-ils.actor.org_types.retrieve",);
974 return $U->get_org_types();
979 __PACKAGE__->register_method(
980 method => "get_user_ident_types",
981 api_name => "open-ils.actor.user.ident_types.retrieve",
984 sub get_user_ident_types {
985 return $ident_types if $ident_types;
986 return $ident_types =
987 new_editor()->retrieve_all_config_identification_type();
993 __PACKAGE__->register_method(
994 method => "get_org_unit",
995 api_name => "open-ils.actor.org_unit.retrieve",
999 my( $self, $client, $user_session, $org_id ) = @_;
1000 my $e = new_editor(authtoken => $user_session);
1002 return $e->event unless $e->checkauth;
1003 $org_id = $e->requestor->ws_ou;
1005 my $o = $e->retrieve_actor_org_unit($org_id)
1006 or return $e->event;
1010 __PACKAGE__->register_method(
1011 method => "search_org_unit",
1012 api_name => "open-ils.actor.org_unit_list.search",
1015 sub search_org_unit {
1017 my( $self, $client, $field, $value ) = @_;
1019 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1021 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1022 { $field => $value } );
1028 # build the org tree
1030 __PACKAGE__->register_method(
1031 method => "get_org_tree",
1032 api_name => "open-ils.actor.org_tree.retrieve",
1034 note => "Returns the entire org tree structure",
1038 my( $self, $client) = @_;
1039 return $U->get_org_tree();
1043 __PACKAGE__->register_method(
1044 method => "get_org_descendants",
1045 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1048 # depth is optional. org_unit is the id
1049 sub get_org_descendants {
1050 my( $self, $client, $org_unit, $depth ) = @_;
1052 if(ref $org_unit eq 'ARRAY') {
1055 for my $i (0..scalar(@$org_unit)-1) {
1056 my $list = $U->simple_scalar_request(
1058 "open-ils.storage.actor.org_unit.descendants.atomic",
1059 $org_unit->[$i], $depth->[$i] );
1060 push(@trees, $U->build_org_tree($list));
1065 my $orglist = $apputils->simple_scalar_request(
1067 "open-ils.storage.actor.org_unit.descendants.atomic",
1068 $org_unit, $depth );
1069 return $U->build_org_tree($orglist);
1074 __PACKAGE__->register_method(
1075 method => "get_org_ancestors",
1076 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1079 # depth is optional. org_unit is the id
1080 sub get_org_ancestors {
1081 my( $self, $client, $org_unit, $depth ) = @_;
1082 my $orglist = $apputils->simple_scalar_request(
1084 "open-ils.storage.actor.org_unit.ancestors.atomic",
1085 $org_unit, $depth );
1086 return $U->build_org_tree($orglist);
1090 __PACKAGE__->register_method(
1091 method => "get_standings",
1092 api_name => "open-ils.actor.standings.retrieve"
1097 return $user_standings if $user_standings;
1098 return $user_standings =
1099 $apputils->simple_scalar_request(
1101 "open-ils.cstore.direct.config.standing.search.atomic",
1102 { id => { "!=" => undef } }
1108 __PACKAGE__->register_method(
1109 method => "get_my_org_path",
1110 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1113 sub get_my_org_path {
1114 my( $self, $client, $auth, $org_id ) = @_;
1115 my $e = new_editor(authtoken=>$auth);
1116 return $e->event unless $e->checkauth;
1117 $org_id = $e->requestor->ws_ou unless defined $org_id;
1119 return $apputils->simple_scalar_request(
1121 "open-ils.storage.actor.org_unit.full_path.atomic",
1126 __PACKAGE__->register_method(
1127 method => "patron_adv_search",
1128 api_name => "open-ils.actor.patron.search.advanced" );
1129 sub patron_adv_search {
1130 my( $self, $client, $auth, $search_hash,
1131 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1133 my $e = new_editor(authtoken=>$auth);
1134 return $e->event unless $e->checkauth;
1135 return $e->event unless $e->allowed('VIEW_USER');
1136 return $U->storagereq(
1137 "open-ils.storage.actor.user.crazy_search", $search_hash,
1138 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1142 __PACKAGE__->register_method(
1143 method => "update_passwd",
1145 api_name => "open-ils.actor.user.password.update");
1147 __PACKAGE__->register_method(
1148 method => "update_passwd",
1149 api_name => "open-ils.actor.user.username.update");
1151 __PACKAGE__->register_method(
1152 method => "update_passwd",
1153 api_name => "open-ils.actor.user.email.update");
1156 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1157 my $e = new_editor(xact=>1, authtoken=>$auth);
1158 return $e->die_event unless $e->checkauth;
1160 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1161 or return $e->die_event;
1162 my $api = $self->api_name;
1164 if( $api =~ /password/o ) {
1166 # make sure the original password matches the in-database password
1167 return OpenILS::Event->new('INCORRECT_PASSWORD')
1168 if md5_hex($orig_pw) ne $db_user->passwd;
1169 $db_user->passwd($new_val);
1173 # if we don't clear the password, the user will be updated with
1174 # a hashed version of the hashed version of their password
1175 $db_user->clear_passwd;
1177 if( $api =~ /username/o ) {
1179 # make sure no one else has this username
1180 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1181 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1182 $db_user->usrname($new_val);
1184 } elsif( $api =~ /email/o ) {
1185 $db_user->email($new_val);
1189 $e->update_actor_user($db_user) or return $e->die_event;
1197 __PACKAGE__->register_method(
1198 method => "check_user_perms",
1199 api_name => "open-ils.actor.user.perm.check",
1200 notes => <<" NOTES");
1201 Takes a login session, user id, an org id, and an array of perm type strings. For each
1202 perm type, if the user does *not* have the given permission it is added
1203 to a list which is returned from the method. If all permissions
1204 are allowed, an empty list is returned
1205 if the logged in user does not match 'user_id', then the logged in user must
1206 have VIEW_PERMISSION priveleges.
1209 sub check_user_perms {
1210 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1212 my( $staff, $evt ) = $apputils->checkses($login_session);
1213 return $evt if $evt;
1215 if($staff->id ne $user_id) {
1216 if( $evt = $apputils->check_perms(
1217 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1223 for my $perm (@$perm_types) {
1224 if($apputils->check_perms($user_id, $org_id, $perm)) {
1225 push @not_allowed, $perm;
1229 return \@not_allowed
1232 __PACKAGE__->register_method(
1233 method => "check_user_perms2",
1234 api_name => "open-ils.actor.user.perm.check.multi_org",
1236 Checks the permissions on a list of perms and orgs for a user
1237 @param authtoken The login session key
1238 @param user_id The id of the user to check
1239 @param orgs The array of org ids
1240 @param perms The array of permission names
1241 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1242 if the logged in user does not match 'user_id', then the logged in user must
1243 have VIEW_PERMISSION priveleges.
1246 sub check_user_perms2 {
1247 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1249 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1250 $authtoken, $user_id, 'VIEW_PERMISSION' );
1251 return $evt if $evt;
1254 for my $org (@$orgs) {
1255 for my $perm (@$perms) {
1256 if($apputils->check_perms($user_id, $org, $perm)) {
1257 push @not_allowed, [ $org, $perm ];
1262 return \@not_allowed
1266 __PACKAGE__->register_method(
1267 method => 'check_user_perms3',
1268 api_name => 'open-ils.actor.user.perm.highest_org',
1270 Returns the highest org unit id at which a user has a given permission
1271 If the requestor does not match the target user, the requestor must have
1272 'VIEW_PERMISSION' rights at the home org unit of the target user
1273 @param authtoken The login session key
1274 @param userid The id of the user in question
1275 @param perm The permission to check
1276 @return The org unit highest in the org tree within which the user has
1277 the requested permission
1280 sub check_user_perms3 {
1281 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1283 my( $staff, $target, $org, $evt );
1285 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1286 $authtoken, $userid, 'VIEW_PERMISSION' );
1287 return $evt if $evt;
1289 my $tree = $U->get_org_tree();
1290 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1294 __PACKAGE__->register_method(
1295 method => 'check_user_work_perms',
1296 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1300 Returns a set of org units which represent the highest orgs in
1301 the org tree where the user has the requested permission. The
1302 purpose of this method is to return the smallest set of org units
1303 which represent the full expanse of the user's ability to perform
1304 the requested action. The user whose perms this method should
1305 check is implied by the authtoken. /,
1307 {desc => 'authtoken', type => 'string'},
1308 {desc => 'permission name', type => 'string'},
1309 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1311 return => {desc => 'An array of org IDs'}
1315 __PACKAGE__->register_method(
1316 method => 'check_user_work_perms',
1317 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1320 @see open-ils.actor.user.work_perm.highest_org_set
1321 Returns a list of org trees. The root of each tree
1322 is the highest org in the organization hierarchy where the user has the
1323 requested permission. Below each tree root is its full tree of descendants.
1327 __PACKAGE__->register_method(
1328 method => 'check_user_work_perms',
1329 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1332 @see open-ils.actor.user.work_perm.highest_org_set
1333 Returns a list of list of all of the org_units where the user
1334 has the requested permission. The first item in each list
1335 is the highest permission org for that section of the
1336 org tree. The remaining items in each sub-list are the
1337 descendants of that org.
1342 __PACKAGE__->register_method(
1343 method => 'check_user_work_perms',
1344 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1347 @see open-ils.actor.user.work_perm.highest_org_set
1348 Returns a list of lists of all of the org_unit IDs where the user
1349 has the requested permission. The first item in each list
1350 is the highest permission org for that section of the
1351 org tree. The remaining items in each sub-list are the
1352 descendants of that org.
1356 sub check_user_work_perms {
1357 my($self, $conn, $auth, $perm, $options) = @_;
1358 my $e = new_editor(authtoken=>$auth);
1359 return $e->event unless $e->checkauth;
1360 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1362 return $orglist if $self->api_name =~ /highest_org_set/;
1364 # build a list of org trees
1365 return get_org_descendants($self, $conn, $orglist)
1366 if $self->api_name =~ /org_tree_list/;
1369 for my $orgid (@$orglist) {
1370 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1371 unshift @sublist, $orgid; # make sure it's at the front of the list
1372 if($self->api_name =~ /org_id_list/) {
1373 push(@list, \@sublist);
1375 push(@list, $e->batch_retrieve_actor_org_unit(\@sublist));
1383 __PACKAGE__->register_method(
1384 method => 'check_user_perms4',
1385 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1387 Returns the highest org unit id at which a user has a given permission
1388 If the requestor does not match the target user, the requestor must have
1389 'VIEW_PERMISSION' rights at the home org unit of the target user
1390 @param authtoken The login session key
1391 @param userid The id of the user in question
1392 @param perms An array of perm names to check
1393 @return An array of orgId's representing the org unit
1394 highest in the org tree within which the user has the requested permission
1395 The arrah of orgId's has matches the order of the perms array
1398 sub check_user_perms4 {
1399 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1401 my( $staff, $target, $org, $evt );
1403 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1404 $authtoken, $userid, 'VIEW_PERMISSION' );
1405 return $evt if $evt;
1408 return [] unless ref($perms);
1409 my $tree = $U->get_org_tree();
1411 for my $p (@$perms) {
1412 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1420 __PACKAGE__->register_method(
1421 method => "user_fines_summary",
1422 api_name => "open-ils.actor.user.fines.summary",
1424 notes => <<" NOTES");
1425 Returns a short summary of the users total open fines, excluding voided fines
1426 Params are login_session, user_id
1427 Returns a 'mous' object.
1430 sub user_fines_summary {
1431 my( $self, $client, $auth, $user_id ) = @_;
1432 my $e = new_editor(authtoken=>$auth);
1433 return $e->event unless $e->checkauth;
1434 my $user = $e->retrieve_actor_user($user_id)
1435 or return $e->event;
1437 if( $user_id ne $e->requestor->id ) {
1438 return $e->event unless
1439 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1442 # run this inside a transaction to prevent replication delay errors
1443 my $ses = $U->start_db_session();
1444 my $s = $ses->request(
1445 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1446 $U->rollback_db_session($ses);
1453 __PACKAGE__->register_method(
1454 method => "user_transactions",
1455 api_name => "open-ils.actor.user.transactions",
1456 notes => <<" NOTES");
1457 Returns a list of open user transactions (mbts objects);
1458 Params are login_session, user_id
1459 Optional third parameter is the transactions type. defaults to all
1462 __PACKAGE__->register_method(
1463 method => "user_transactions",
1464 api_name => "open-ils.actor.user.transactions.have_charge",
1465 notes => <<" NOTES");
1466 Returns a list of all open user transactions (mbts objects) that have an initial charge
1467 Params are login_session, user_id
1468 Optional third parameter is the transactions type. defaults to all
1471 __PACKAGE__->register_method(
1472 method => "user_transactions",
1473 api_name => "open-ils.actor.user.transactions.have_balance",
1474 notes => <<" NOTES");
1475 Returns a list of all open user transactions (mbts objects) that have a balance
1476 Params are login_session, user_id
1477 Optional third parameter is the transactions type. defaults to all
1480 __PACKAGE__->register_method(
1481 method => "user_transactions",
1482 api_name => "open-ils.actor.user.transactions.fleshed",
1483 notes => <<" NOTES");
1484 Returns an object/hash of transaction, circ, title where transaction = an open
1485 user transactions (mbts objects), circ is the attached circluation, and title
1486 is the title the circ points to
1487 Params are login_session, user_id
1488 Optional third parameter is the transactions type. defaults to all
1491 __PACKAGE__->register_method(
1492 method => "user_transactions",
1493 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1494 notes => <<" NOTES");
1495 Returns an object/hash of transaction, circ, title where transaction = an open
1496 user transactions that has an initial charge (mbts objects), circ is the
1497 attached circluation, and title is the title the circ points to
1498 Params are login_session, user_id
1499 Optional third parameter is the transactions type. defaults to all
1502 __PACKAGE__->register_method(
1503 method => "user_transactions",
1504 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1505 notes => <<" NOTES");
1506 Returns an object/hash of transaction, circ, title where transaction = an open
1507 user transaction that has a balance (mbts objects), circ is the attached
1508 circluation, and title is the title the circ points to
1509 Params are login_session, user_id
1510 Optional third parameter is the transaction type. defaults to all
1513 __PACKAGE__->register_method(
1514 method => "user_transactions",
1515 api_name => "open-ils.actor.user.transactions.count",
1516 notes => <<" NOTES");
1517 Returns an object/hash of transaction, circ, title where transaction = an open
1518 user transactions (mbts objects), circ is the attached circluation, and title
1519 is the title the circ points to
1520 Params are login_session, user_id
1521 Optional third parameter is the transactions type. defaults to all
1524 __PACKAGE__->register_method(
1525 method => "user_transactions",
1526 api_name => "open-ils.actor.user.transactions.have_charge.count",
1527 notes => <<" NOTES");
1528 Returns an object/hash of transaction, circ, title where transaction = an open
1529 user transactions that has an initial charge (mbts objects), circ is the
1530 attached circluation, and title is the title the circ points to
1531 Params are login_session, user_id
1532 Optional third parameter is the transactions type. defaults to all
1535 __PACKAGE__->register_method(
1536 method => "user_transactions",
1537 api_name => "open-ils.actor.user.transactions.have_balance.count",
1538 notes => <<" NOTES");
1539 Returns an object/hash of transaction, circ, title where transaction = an open
1540 user transaction that has a balance (mbts objects), circ is the attached
1541 circluation, and title is the title the circ points to
1542 Params are login_session, user_id
1543 Optional third parameter is the transaction type. defaults to all
1546 __PACKAGE__->register_method(
1547 method => "user_transactions",
1548 api_name => "open-ils.actor.user.transactions.have_balance.total",
1549 notes => <<" NOTES");
1550 Returns an object/hash of transaction, circ, title where transaction = an open
1551 user transaction that has a balance (mbts objects), circ is the attached
1552 circluation, and title is the title the circ points to
1553 Params are login_session, user_id
1554 Optional third parameter is the transaction type. defaults to all
1559 sub user_transactions {
1560 my( $self, $client, $login_session, $user_id, $type ) = @_;
1562 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1563 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1564 return $evt if $evt;
1566 my $api = $self->api_name();
1570 if(defined($type)) { @xact = (xact_type => $type);
1572 } else { @xact = (); }
1575 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1576 ->run($login_session => $user_id => $type);
1578 if($api =~ /have_charge/o) {
1580 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1582 } elsif($api =~ /have_balance/o) {
1584 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1587 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1591 if($api =~ /total/o) {
1593 for my $t (@$trans) {
1594 $total += $t->balance_owed;
1597 $logger->debug("Total balance owed by user $user_id: $total");
1601 if($api =~ /count/o) { return scalar @$trans; }
1602 if($api !~ /fleshed/o) { return $trans; }
1605 for my $t (@$trans) {
1607 if( $t->xact_type ne 'circulation' ) {
1608 push @resp, {transaction => $t};
1612 my $circ = $apputils->simple_scalar_request(
1614 "open-ils.cstore.direct.action.circulation.retrieve",
1619 my $title = $apputils->simple_scalar_request(
1621 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1622 $circ->target_copy );
1626 my $u = OpenILS::Utils::ModsParser->new();
1627 $u->start_mods_batch($title->marc());
1628 my $mods = $u->finish_mods_batch();
1629 $mods->doc_id($title->id) if $mods;
1631 push @resp, {transaction => $t, circ => $circ, record => $mods };
1639 __PACKAGE__->register_method(
1640 method => "user_transaction_retrieve",
1641 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1643 notes => <<" NOTES");
1644 Returns a fleshedtransaction record
1646 __PACKAGE__->register_method(
1647 method => "user_transaction_retrieve",
1648 api_name => "open-ils.actor.user.transaction.retrieve",
1650 notes => <<" NOTES");
1651 Returns a transaction record
1653 sub user_transaction_retrieve {
1654 my( $self, $client, $login_session, $bill_id ) = @_;
1656 # XXX I think I'm deprecated... make sure
1658 my $trans = $apputils->simple_scalar_request(
1660 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1664 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1665 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1666 return $evt if $evt;
1668 my $api = $self->api_name();
1669 if($api !~ /fleshed/o) { return $trans; }
1671 if( $trans->xact_type ne 'circulation' ) {
1672 $logger->debug("Returning non-circ transaction");
1673 return {transaction => $trans};
1676 my $circ = $apputils->simple_scalar_request(
1678 "open-ils..direct.action.circulation.retrieve",
1681 return {transaction => $trans} unless $circ;
1682 $logger->debug("Found the circ transaction");
1684 my $title = $apputils->simple_scalar_request(
1686 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1687 $circ->target_copy );
1689 return {transaction => $trans, circ => $circ } unless $title;
1690 $logger->debug("Found the circ title");
1694 my $u = OpenILS::Utils::ModsParser->new();
1695 $u->start_mods_batch($title->marc());
1696 $mods = $u->finish_mods_batch();
1698 if ($title->id == OILS_PRECAT_RECORD) {
1699 my $copy = $apputils->simple_scalar_request(
1701 "open-ils.cstore.direct.asset.copy.retrieve",
1702 $circ->target_copy );
1704 $mods = new Fieldmapper::metabib::virtual_record;
1705 $mods->doc_id(OILS_PRECAT_RECORD);
1706 $mods->title($copy->dummy_title);
1707 $mods->author($copy->dummy_author);
1711 $logger->debug("MODSized the circ title");
1713 return {transaction => $trans, circ => $circ, record => $mods };
1717 __PACKAGE__->register_method(
1718 method => "hold_request_count",
1719 api_name => "open-ils.actor.user.hold_requests.count",
1722 notes => <<" NOTES");
1723 Returns hold ready/total counts
1725 sub hold_request_count {
1726 my( $self, $client, $login_session, $userid ) = @_;
1728 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1729 $login_session, $userid, 'VIEW_HOLD' );
1730 return $evt if $evt;
1733 my $holds = $apputils->simple_scalar_request(
1735 "open-ils.cstore.direct.action.hold_request.search.atomic",
1738 fulfillment_time => {"=" => undef },
1739 cancel_time => undef,
1744 for my $h (@$holds) {
1745 next unless $h->capture_time and $h->current_copy;
1747 my $copy = $apputils->simple_scalar_request(
1749 "open-ils.cstore.direct.asset.copy.retrieve",
1753 if ($copy and $copy->status == 8) {
1758 return { total => scalar(@$holds), ready => scalar(@ready) };
1762 __PACKAGE__->register_method(
1763 method => "checkedout_count",
1764 api_name => "open-ils.actor.user.checked_out.count__",
1766 notes => <<" NOTES");
1767 Returns a transaction record
1771 sub checkedout_count {
1772 my( $self, $client, $login_session, $userid ) = @_;
1774 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1775 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1776 return $evt if $evt;
1778 my $circs = $apputils->simple_scalar_request(
1780 "open-ils.cstore.direct.action.circulation.search.atomic",
1781 { usr => $userid, stop_fines => undef }
1782 #{ usr => $userid, checkin_time => {"=" => undef } }
1785 my $parser = DateTime::Format::ISO8601->new;
1788 for my $c (@$circs) {
1789 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1790 my $due = $due_dt->epoch;
1792 if ($due < DateTime->today->epoch) {
1797 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1801 __PACKAGE__->register_method(
1802 method => "checked_out",
1803 api_name => "open-ils.actor.user.checked_out",
1807 Returns a structure of circulations objects sorted by
1808 out, overdue, lost, claims_returned, long_overdue.
1809 A list of IDs are returned of each type.
1810 lost, long_overdue, and claims_returned circ will not
1811 be "finished" (there is an outstanding balance or some
1812 other pending action on the circ).
1814 The .count method also includes a 'total' field which
1815 sums all "open" circs
1819 __PACKAGE__->register_method(
1820 method => "checked_out",
1821 api_name => "open-ils.actor.user.checked_out.count",
1824 signature => q/@see open-ils.actor.user.checked_out/
1828 my( $self, $conn, $auth, $userid ) = @_;
1830 my $e = new_editor(authtoken=>$auth);
1831 return $e->event unless $e->checkauth;
1833 if( $userid ne $e->requestor->id ) {
1834 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1837 my $count = $self->api_name =~ /count/;
1838 return _checked_out( $count, $e, $userid );
1842 my( $iscount, $e, $userid ) = @_;
1845 my $meth = 'open-ils.storage.actor.user.checked_out';
1846 $meth = "$meth.count" if $iscount;
1847 return $U->storagereq($meth, $userid);
1849 # XXX Old code - moved to storage
1850 #------------------------------------------------------------------------------
1851 #------------------------------------------------------------------------------
1852 my $circs = $e->search_action_circulation(
1853 { usr => $userid, checkin_time => undef });
1855 my $parser = DateTime::Format::ISO8601->new;
1857 # split the circs up into overdue and not-overdue circs
1859 for my $c (@$circs) {
1860 if( $c->due_date ) {
1861 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1862 my $due = $due_dt->epoch;
1863 if ($due < DateTime->today->epoch) {
1873 my( @open, @od, @lost, @cr, @lo );
1875 while (my $c = shift(@out)) {
1876 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1877 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1878 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1879 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1882 while (my $c = shift(@overdue)) {
1883 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1884 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1885 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1886 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1891 total => @open + @od + @lost + @cr + @lo,
1892 out => scalar(@open),
1893 overdue => scalar(@od),
1894 lost => scalar(@lost),
1895 claims_returned => scalar(@cr),
1896 long_overdue => scalar(@lo)
1904 claims_returned => \@cr,
1905 long_overdue => \@lo
1910 sub _checked_out_WHAT {
1911 my( $iscount, $e, $userid ) = @_;
1913 my $circs = $e->search_action_circulation(
1914 { usr => $userid, stop_fines => undef });
1916 my $mcircs = $e->search_action_circulation(
1919 checkin_time => undef,
1920 xact_finish => undef,
1924 push( @$circs, @$mcircs );
1926 my $parser = DateTime::Format::ISO8601->new;
1928 # split the circs up into overdue and not-overdue circs
1930 for my $c (@$circs) {
1931 if( $c->due_date ) {
1932 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1933 my $due = $due_dt->epoch;
1934 if ($due < DateTime->today->epoch) {
1935 push @overdue, $c->id;
1944 # grab all of the lost, claims-returned, and longoverdue circs
1945 #my $open = $e->search_action_circulation(
1946 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1949 # these items have stop_fines, but no xact_finish, so money
1950 # is owed on them and they have not been checked in
1951 my $open = $e->search_action_circulation(
1954 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1955 xact_finish => undef,
1956 checkin_time => undef,
1961 my( @lost, @cr, @lo );
1962 for my $c (@$open) {
1963 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1964 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1965 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1971 total => @$circs + @lost + @cr + @lo,
1972 out => scalar(@out),
1973 overdue => scalar(@overdue),
1974 lost => scalar(@lost),
1975 claims_returned => scalar(@cr),
1976 long_overdue => scalar(@lo)
1982 overdue => \@overdue,
1984 claims_returned => \@cr,
1985 long_overdue => \@lo
1991 __PACKAGE__->register_method(
1992 method => "checked_in_with_fines",
1993 api_name => "open-ils.actor.user.checked_in_with_fines",
1996 signature => q/@see open-ils.actor.user.checked_out/
1998 sub checked_in_with_fines {
1999 my( $self, $conn, $auth, $userid ) = @_;
2001 my $e = new_editor(authtoken=>$auth);
2002 return $e->event unless $e->checkauth;
2004 if( $userid ne $e->requestor->id ) {
2005 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2008 # money is owed on these items and they are checked in
2009 my $open = $e->search_action_circulation(
2012 xact_finish => undef,
2013 checkin_time => { "!=" => undef },
2018 my( @lost, @cr, @lo );
2019 for my $c (@$open) {
2020 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2021 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2022 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2027 claims_returned => \@cr,
2028 long_overdue => \@lo
2040 __PACKAGE__->register_method(
2041 method => "user_transaction_history",
2042 api_name => "open-ils.actor.user.transactions.history",
2044 notes => <<" NOTES");
2045 Returns a list of billable transaction ids for a user, optionally by type
2047 __PACKAGE__->register_method(
2048 method => "user_transaction_history",
2049 api_name => "open-ils.actor.user.transactions.history.have_charge",
2051 notes => <<" NOTES");
2052 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2054 __PACKAGE__->register_method(
2055 method => "user_transaction_history",
2056 api_name => "open-ils.actor.user.transactions.history.have_balance",
2059 notes => <<" NOTES");
2060 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2062 __PACKAGE__->register_method(
2063 method => "user_transaction_history",
2064 api_name => "open-ils.actor.user.transactions.history.still_open",
2066 notes => <<" NOTES");
2067 Returns a list of billable transaction ids for a user that are not finished
2069 __PACKAGE__->register_method(
2070 method => "user_transaction_history",
2071 api_name => "open-ils.actor.user.transactions.history.have_bill",
2074 notes => <<" NOTES");
2075 Returns a list of billable transaction ids for a user that has billings
2081 sub _user_transaction_history {
2082 my( $self, $client, $login_session, $user_id, $type ) = @_;
2084 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2085 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2086 return $evt if $evt;
2088 my $api = $self->api_name();
2093 @xact = (xact_type => $type) if(defined($type));
2094 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2095 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2097 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2099 my $trans = $apputils->simple_scalar_request(
2101 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2102 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2104 return [ map { $_->id } @$trans ];
2108 =head SEE APPUTILS.PM
2113 for my $x (@xacts) {
2114 my $s = new Fieldmapper::money::billable_transaction_summary;
2117 $s->xact_start( $x->xact_start );
2118 $s->xact_finish( $x->xact_finish );
2122 for my $b (@{ $x->billings }) {
2123 next if ($U->is_true($b->voided));
2124 $to += ($b->amount * 100);
2125 $lb ||= $b->billing_ts;
2126 if ($b->billing_ts ge $lb) {
2127 $lb = $b->billing_ts;
2128 $s->last_billing_note($b->note);
2129 $s->last_billing_ts($b->billing_ts);
2130 $s->last_billing_type($b->billing_type);
2134 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2138 for my $p (@{ $x->payments }) {
2139 next if ($U->is_true($p->voided));
2140 $tp += ($p->amount * 100);
2141 $lp ||= $p->payment_ts;
2142 if ($p->payment_ts ge $lp) {
2143 $lp = $p->payment_ts;
2144 $s->last_payment_note($p->note);
2145 $s->last_payment_ts($p->payment_ts);
2146 $s->last_payment_type($p->payment_type);
2149 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2151 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2153 $s->xact_type( 'grocery' ) if ($x->grocery);
2154 $s->xact_type( 'circulation' ) if ($x->circulation);
2163 sub user_transaction_history {
2164 my( $self, $conn, $auth, $userid, $type ) = @_;
2166 # run inside of a transaction to prevent replication delays
2167 my $e = new_editor(xact=>1, authtoken=>$auth);
2168 return $e->die_event unless $e->checkauth;
2170 if( $e->requestor->id ne $userid ) {
2171 return $e->die_event
2172 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2175 my $api = $self->api_name;
2176 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2178 my @xacts = @{ $e->search_money_billable_transaction(
2179 [ { usr => $userid, @xact_finish },
2181 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2182 order_by => { mbt => 'xact_start DESC' },
2190 #my @mbts = _make_mbts( @xacts );
2191 my @mbts = $U->make_mbts( @xacts );
2193 if(defined($type)) {
2194 @mbts = grep { $_->xact_type eq $type } @mbts;
2197 if($api =~ /have_balance/o) {
2198 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2201 if($api =~ /have_charge/o) {
2202 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2205 if($api =~ /have_bill/o) {
2206 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2214 __PACKAGE__->register_method(
2215 method => "user_perms",
2216 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2218 notes => <<" NOTES");
2219 Returns a list of permissions
2222 my( $self, $client, $authtoken, $user ) = @_;
2224 my( $staff, $evt ) = $apputils->checkses($authtoken);
2225 return $evt if $evt;
2227 $user ||= $staff->id;
2229 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2233 return $apputils->simple_scalar_request(
2235 "open-ils.storage.permission.user_perms.atomic",
2239 __PACKAGE__->register_method(
2240 method => "retrieve_perms",
2241 api_name => "open-ils.actor.permissions.retrieve",
2242 notes => <<" NOTES");
2243 Returns a list of permissions
2245 sub retrieve_perms {
2246 my( $self, $client ) = @_;
2247 return $apputils->simple_scalar_request(
2249 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2250 { id => { '!=' => undef } }
2254 __PACKAGE__->register_method(
2255 method => "retrieve_groups",
2256 api_name => "open-ils.actor.groups.retrieve",
2257 notes => <<" NOTES");
2258 Returns a list of user groupss
2260 sub retrieve_groups {
2261 my( $self, $client ) = @_;
2262 return new_editor()->retrieve_all_permission_grp_tree();
2265 __PACKAGE__->register_method(
2266 method => "retrieve_org_address",
2267 api_name => "open-ils.actor.org_unit.address.retrieve",
2268 notes => <<' NOTES');
2269 Returns an org_unit address by ID
2270 @param An org_address ID
2272 sub retrieve_org_address {
2273 my( $self, $client, $id ) = @_;
2274 return $apputils->simple_scalar_request(
2276 "open-ils.cstore.direct.actor.org_address.retrieve",
2281 __PACKAGE__->register_method(
2282 method => "retrieve_groups_tree",
2283 api_name => "open-ils.actor.groups.tree.retrieve",
2284 notes => <<" NOTES");
2285 Returns a list of user groups
2287 sub retrieve_groups_tree {
2288 my( $self, $client ) = @_;
2289 return new_editor()->search_permission_grp_tree(
2294 flesh_fields => { pgt => ["children"] },
2295 order_by => { pgt => 'name'}
2302 # turns an org list into an org tree
2304 sub build_group_tree {
2306 my( $self, $grplist) = @_;
2308 return $grplist unless (
2309 ref($grplist) and @$grplist > 1 );
2311 my @list = sort { $a->name cmp $b->name } @$grplist;
2314 for my $grp (@list) {
2316 if ($grp and !defined($grp->parent)) {
2320 my ($parent) = grep { $_->id == $grp->parent} @list;
2322 $parent->children([]) unless defined($parent->children);
2323 push( @{$parent->children}, $grp );
2331 __PACKAGE__->register_method(
2332 method => "add_user_to_groups",
2333 api_name => "open-ils.actor.user.set_groups",
2334 notes => <<" NOTES");
2335 Adds a user to one or more permission groups
2338 sub add_user_to_groups {
2339 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2341 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2342 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2343 return $evt if $evt;
2345 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2346 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2347 return $evt if $evt;
2349 $apputils->simplereq(
2351 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2353 for my $group (@$groups) {
2354 my $link = Fieldmapper::permission::usr_grp_map->new;
2356 $link->usr($userid);
2358 my $id = $apputils->simplereq(
2360 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2366 __PACKAGE__->register_method(
2367 method => "get_user_perm_groups",
2368 api_name => "open-ils.actor.user.get_groups",
2369 notes => <<" NOTES");
2370 Retrieve a user's permission groups.
2374 sub get_user_perm_groups {
2375 my( $self, $client, $authtoken, $userid ) = @_;
2377 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2378 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2379 return $evt if $evt;
2381 return $apputils->simplereq(
2383 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2387 __PACKAGE__->register_method(
2388 method => "get_user_work_ous",
2389 api_name => "open-ils.actor.user.get_work_ous",
2390 notes => <<" NOTES");
2391 Retrieve a user's work org units.
2393 __PACKAGE__->register_method(
2394 method => "get_user_work_ous",
2395 api_name => "open-ils.actor.user.get_work_ous.ids",
2396 notes => <<" NOTES");
2397 Retrieve a user's work org units.
2401 sub get_user_work_ous {
2402 my( $self, $client, $auth, $userid ) = @_;
2403 my $e = new_editor(authtoken=>$auth);
2404 return $e->event unless $e->checkauth;
2405 $userid ||= $e->requestor->id;
2407 if($e->requestor->id != $userid) {
2408 my $user = $e->retrieve_actor_user($userid)
2409 or return $e->event;
2410 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2413 return $e->search_permission_usr_work_ou_map({usr => $userid})
2414 unless $self->api_name =~ /.ids$/;
2416 # client just wants a list of org IDs
2417 return $U->get_user_work_ou_ids($e, $userid);
2423 __PACKAGE__->register_method (
2424 method => 'register_workstation',
2425 api_name => 'open-ils.actor.workstation.register.override',
2426 signature => q/@see open-ils.actor.workstation.register/);
2428 __PACKAGE__->register_method (
2429 method => 'register_workstation',
2430 api_name => 'open-ils.actor.workstation.register',
2432 Registers a new workstion in the system
2433 @param authtoken The login session key
2434 @param name The name of the workstation id
2435 @param owner The org unit that owns this workstation
2436 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2437 if the name is already in use.
2440 sub register_workstation {
2441 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2443 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2444 return $e->die_event unless $e->checkauth;
2445 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2446 my $existing = $e->search_actor_workstation({name => $name})->[0];
2450 if( $self->api_name =~ /override/o ) {
2451 # workstation with the given name exists.
2453 if($owner ne $existing->owning_lib) {
2454 # if necessary, update the owning_lib of the workstation
2456 $logger->info("changing owning lib of workstation ".$existing->id.
2457 " from ".$existing->owning_lib." to $owner");
2458 return $e->die_event unless
2459 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2461 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2463 $existing->owning_lib($owner);
2464 return $e->die_event unless $e->update_actor_workstation($existing);
2470 "attempt to register an existing workstation. returning existing ID");
2473 return $existing->id;
2476 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2480 my $ws = Fieldmapper::actor::workstation->new;
2481 $ws->owning_lib($owner);
2483 $e->create_actor_workstation($ws) or return $e->die_event;
2485 return $ws->id; # note: editor sets the id on the new object for us
2488 __PACKAGE__->register_method (
2489 method => 'workstation_list',
2490 api_name => 'open-ils.actor.workstation.list',
2492 Returns a list of workstations registered at the given location
2493 @param authtoken The login session key
2494 @param ids A list of org_unit.id's for the workstation owners
2497 sub workstation_list {
2498 my( $self, $conn, $authtoken, @orgs ) = @_;
2500 my $e = new_editor(authtoken=>$authtoken);
2501 return $e->event unless $e->checkauth;
2506 unless $e->allowed('REGISTER_WORKSTATION', $o);
2507 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2518 __PACKAGE__->register_method (
2519 method => 'fetch_patron_note',
2520 api_name => 'open-ils.actor.note.retrieve.all',
2523 Returns a list of notes for a given user
2524 Requestor must have VIEW_USER permission if pub==false and
2525 @param authtoken The login session key
2526 @param args Hash of params including
2527 patronid : the patron's id
2528 pub : true if retrieving only public notes
2532 sub fetch_patron_note {
2533 my( $self, $conn, $authtoken, $args ) = @_;
2534 my $patronid = $$args{patronid};
2536 my($reqr, $evt) = $U->checkses($authtoken);
2537 return $evt if $evt;
2540 ($patron, $evt) = $U->fetch_user($patronid);
2541 return $evt if $evt;
2544 if( $patronid ne $reqr->id ) {
2545 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2546 return $evt if $evt;
2548 return $U->cstorereq(
2549 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2550 { usr => $patronid, pub => 't' } );
2553 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2554 return $evt if $evt;
2556 return $U->cstorereq(
2557 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2560 __PACKAGE__->register_method (
2561 method => 'create_user_note',
2562 api_name => 'open-ils.actor.note.create',
2564 Creates a new note for the given user
2565 @param authtoken The login session key
2566 @param note The note object
2569 sub create_user_note {
2570 my( $self, $conn, $authtoken, $note ) = @_;
2571 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2572 return $e->die_event unless $e->checkauth;
2574 my $user = $e->retrieve_actor_user($note->usr)
2575 or return $e->die_event;
2577 return $e->die_event unless
2578 $e->allowed('UPDATE_USER',$user->home_ou);
2580 $note->creator($e->requestor->id);
2581 $e->create_actor_usr_note($note) or return $e->die_event;
2587 __PACKAGE__->register_method (
2588 method => 'delete_user_note',
2589 api_name => 'open-ils.actor.note.delete',
2591 Deletes a note for the given user
2592 @param authtoken The login session key
2593 @param noteid The note id
2596 sub delete_user_note {
2597 my( $self, $conn, $authtoken, $noteid ) = @_;
2599 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2600 return $e->die_event unless $e->checkauth;
2601 my $note = $e->retrieve_actor_usr_note($noteid)
2602 or return $e->die_event;
2603 my $user = $e->retrieve_actor_user($note->usr)
2604 or return $e->die_event;
2605 return $e->die_event unless
2606 $e->allowed('UPDATE_USER', $user->home_ou);
2608 $e->delete_actor_usr_note($note) or return $e->die_event;
2614 __PACKAGE__->register_method (
2615 method => 'update_user_note',
2616 api_name => 'open-ils.actor.note.update',
2618 @param authtoken The login session key
2619 @param note The note
2623 sub update_user_note {
2624 my( $self, $conn, $auth, $note ) = @_;
2625 my $e = new_editor(authtoken=>$auth, xact=>1);
2626 return $e->event unless $e->checkauth;
2627 my $patron = $e->retrieve_actor_user($note->usr)
2628 or return $e->event;
2629 return $e->event unless
2630 $e->allowed('UPDATE_USER', $patron->home_ou);
2631 $e->update_actor_user_note($note)
2632 or return $e->event;
2640 __PACKAGE__->register_method (
2641 method => 'create_closed_date',
2642 api_name => 'open-ils.actor.org_unit.closed_date.create',
2644 Creates a new closing entry for the given org_unit
2645 @param authtoken The login session key
2646 @param note The closed_date object
2649 sub create_closed_date {
2650 my( $self, $conn, $authtoken, $cd ) = @_;
2652 my( $user, $evt ) = $U->checkses($authtoken);
2653 return $evt if $evt;
2655 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2656 return $evt if $evt;
2658 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2660 my $id = $U->storagereq(
2661 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2662 return $U->DB_UPDATE_FAILED($cd) unless $id;
2667 __PACKAGE__->register_method (
2668 method => 'delete_closed_date',
2669 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2671 Deletes a closing entry for the given org_unit
2672 @param authtoken The login session key
2673 @param noteid The close_date id
2676 sub delete_closed_date {
2677 my( $self, $conn, $authtoken, $cd ) = @_;
2679 my( $user, $evt ) = $U->checkses($authtoken);
2680 return $evt if $evt;
2683 ($cd_obj, $evt) = fetch_closed_date($cd);
2684 return $evt if $evt;
2686 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2687 return $evt if $evt;
2689 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2691 my $stat = $U->storagereq(
2692 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2693 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2698 __PACKAGE__->register_method(
2699 method => 'usrname_exists',
2700 api_name => 'open-ils.actor.username.exists',
2702 Returns 1 if the requested username exists, returns 0 otherwise
2706 sub usrname_exists {
2707 my( $self, $conn, $auth, $usrname ) = @_;
2708 my $e = new_editor(authtoken=>$auth);
2709 return $e->event unless $e->checkauth;
2710 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2711 return $$a[0] if $a and @$a;
2715 __PACKAGE__->register_method(
2716 method => 'barcode_exists',
2717 api_name => 'open-ils.actor.barcode.exists',
2720 Returns 1 if the requested barcode exists, returns 0 otherwise
2724 sub barcode_exists {
2725 my( $self, $conn, $auth, $barcode ) = @_;
2726 my $e = new_editor(authtoken=>$auth);
2727 return $e->event unless $e->checkauth;
2728 my $card = $e->search_actor_card({barcode => $barcode});
2729 return undef unless @$card;
2730 return $card->[0]->usr;
2734 __PACKAGE__->register_method(
2735 method => 'retrieve_net_levels',
2736 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2739 sub retrieve_net_levels {
2740 my( $self, $conn, $auth ) = @_;
2741 my $e = new_editor(authtoken=>$auth);
2742 return $e->event unless $e->checkauth;
2743 return $e->retrieve_all_config_net_access_level();
2747 __PACKAGE__->register_method(
2748 method => 'fetch_org_by_shortname',
2749 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2751 sub fetch_org_by_shortname {
2752 my( $self, $conn, $sname ) = @_;
2753 my $e = new_editor();
2754 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2755 return $e->event unless $org;
2760 __PACKAGE__->register_method(
2761 method => 'session_home_lib',
2762 api_name => 'open-ils.actor.session.home_lib',
2765 sub session_home_lib {
2766 my( $self, $conn, $auth ) = @_;
2767 my $e = new_editor(authtoken=>$auth);
2768 return undef unless $e->checkauth;
2769 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2770 return $org->shortname;
2773 __PACKAGE__->register_method(
2774 method => 'session_safe_token',
2775 api_name => 'open-ils.actor.session.safe_token',
2777 Returns a hashed session ID that is safe for export to the world.
2778 This safe token will expire after 1 hour of non-use.
2779 @param auth Active authentication token
2783 sub session_safe_token {
2784 my( $self, $conn, $auth ) = @_;
2785 my $e = new_editor(authtoken=>$auth);
2786 return undef unless $e->checkauth;
2788 my $safe_token = md5_hex($auth);
2790 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2792 # Add more like the following if needed...
2794 "safe-token-home_lib-shortname-$safe_token",
2795 $e->retrieve_actor_org_unit(
2796 $e->requestor->home_ou
2805 __PACKAGE__->register_method(
2806 method => 'safe_token_home_lib',
2807 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2809 Returns the home library shortname from the session
2810 asscociated with a safe token from generated by
2811 open-ils.actor.session.safe_token.
2812 @param safe_token Active safe token
2816 sub safe_token_home_lib {
2817 my( $self, $conn, $safe_token ) = @_;
2819 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2820 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2825 __PACKAGE__->register_method(
2826 method => 'slim_tree',
2827 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2830 my $tree = new_editor()->search_actor_org_unit(
2832 {"parent_ou" => undef },
2835 flesh_fields => { aou => ['children'] },
2836 order_by => { aou => 'name'},
2837 select => { aou => ["id","shortname", "name"]},
2842 return trim_tree($tree);
2848 return undef unless $tree;
2850 code => $tree->shortname,
2851 name => $tree->name,
2853 if( $tree->children and @{$tree->children} ) {
2854 $htree->{children} = [];
2855 for my $c (@{$tree->children}) {
2856 push( @{$htree->{children}}, trim_tree($c) );
2864 __PACKAGE__->register_method(
2865 method => "update_penalties",
2866 api_name => "open-ils.actor.user.penalties.update");
2867 sub update_penalties {
2868 my( $self, $conn, $auth, $userid ) = @_;
2869 my $e = new_editor(authtoken=>$auth);
2870 return $e->event unless $e->checkauth;
2871 $U->update_patron_penalties(
2873 patronid => $userid,
2880 __PACKAGE__->register_method(
2881 method => "user_retrieve_fleshed_by_id",
2882 api_name => "open-ils.actor.user.fleshed.retrieve",);
2884 sub user_retrieve_fleshed_by_id {
2885 my( $self, $client, $auth, $user_id, $fields ) = @_;
2886 my $e = new_editor(authtoken => $auth);
2887 return $e->event unless $e->checkauth;
2889 if( $e->requestor->id != $user_id ) {
2890 return $e->event unless $e->allowed('VIEW_USER');
2896 "standing_penalties",
2900 "stat_cat_entries" ];
2901 return new_flesh_user($user_id, $fields, $e);
2905 sub new_flesh_user {
2908 my $fields = shift || [];
2909 my $e = shift || new_editor(xact=>1);
2911 my $user = $e->retrieve_actor_user(
2916 "flesh_fields" => { "au" => $fields }
2919 ) or return $e->event;
2922 if( grep { $_ eq 'addresses' } @$fields ) {
2924 $user->addresses([]) unless @{$user->addresses};
2926 if( ref $user->billing_address ) {
2927 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2928 push( @{$user->addresses}, $user->billing_address );
2932 if( ref $user->mailing_address ) {
2933 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2934 push( @{$user->addresses}, $user->mailing_address );
2940 $user->clear_passwd();
2947 __PACKAGE__->register_method(
2948 method => "user_retrieve_parts",
2949 api_name => "open-ils.actor.user.retrieve.parts",);
2951 sub user_retrieve_parts {
2952 my( $self, $client, $auth, $user_id, $fields ) = @_;
2953 my $e = new_editor(authtoken => $auth);
2954 return $e->event unless $e->checkauth;
2955 if( $e->requestor->id != $user_id ) {
2956 return $e->event unless $e->allowed('VIEW_USER');
2959 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2960 push(@resp, $user->$_()) for(@$fields);
2966 __PACKAGE__->register_method(
2967 method => 'user_opt_in_enabled',
2968 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2970 @return 1 if user opt-in is globally enabled, 0 otherwise.
2973 sub user_opt_in_enabled {
2974 my($self, $conn) = @_;
2975 my $sc = OpenSRF::Utils::SettingsClient->new;
2976 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2981 __PACKAGE__->register_method(
2982 method => 'user_opt_in_at_org',
2983 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2985 @param $auth The auth token
2986 @param user_id The ID of the user to test
2987 @return 1 if the user has opted in at the specified org,
2988 event on error, and 0 otherwise. /);
2989 sub user_opt_in_at_org {
2990 my($self, $conn, $auth, $user_id) = @_;
2992 # see if we even need to enforce the opt-in value
2993 return 1 unless user_opt_in_enabled($self);
2995 my $e = new_editor(authtoken => $auth);
2996 return $e->event unless $e->checkauth;
2997 my $org_id = $e->requestor->ws_ou;
2999 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3000 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3002 # user is automatically opted-in at the home org
3003 return 1 if $user->home_ou eq $org_id;
3005 my $vals = $e->search_actor_usr_org_unit_opt_in(
3006 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3012 __PACKAGE__->register_method(
3013 method => 'create_user_opt_in_at_org',
3014 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3016 @param $auth The auth token
3017 @param user_id The ID of the user to test
3018 @return The ID of the newly created object, event on error./);
3020 sub create_user_opt_in_at_org {
3021 my($self, $conn, $auth, $user_id) = @_;
3023 my $e = new_editor(authtoken => $auth, xact=>1);
3024 return $e->die_event unless $e->checkauth;
3025 my $org_id = $e->requestor->ws_ou;
3027 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3028 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3030 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3032 $opt_in->org_unit($org_id);
3033 $opt_in->usr($user_id);
3034 $opt_in->staff($e->requestor->id);
3035 $opt_in->opt_in_ts('now');
3036 $opt_in->opt_in_ws($e->requestor->wsid);
3038 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3039 or return $e->die_event;