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",
1040 return $U->get_org_tree($client->session->session_locale);
1044 __PACKAGE__->register_method(
1045 method => "get_org_descendants",
1046 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1049 # depth is optional. org_unit is the id
1050 sub get_org_descendants {
1051 my( $self, $client, $org_unit, $depth ) = @_;
1053 if(ref $org_unit eq 'ARRAY') {
1056 for my $i (0..scalar(@$org_unit)-1) {
1057 my $list = $U->simple_scalar_request(
1059 "open-ils.storage.actor.org_unit.descendants.atomic",
1060 $org_unit->[$i], $depth->[$i] );
1061 push(@trees, $U->build_org_tree($list));
1066 my $orglist = $apputils->simple_scalar_request(
1068 "open-ils.storage.actor.org_unit.descendants.atomic",
1069 $org_unit, $depth );
1070 return $U->build_org_tree($orglist);
1075 __PACKAGE__->register_method(
1076 method => "get_org_ancestors",
1077 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1080 # depth is optional. org_unit is the id
1081 sub get_org_ancestors {
1082 my( $self, $client, $org_unit, $depth ) = @_;
1083 my $orglist = $apputils->simple_scalar_request(
1085 "open-ils.storage.actor.org_unit.ancestors.atomic",
1086 $org_unit, $depth );
1087 return $U->build_org_tree($orglist);
1091 __PACKAGE__->register_method(
1092 method => "get_standings",
1093 api_name => "open-ils.actor.standings.retrieve"
1098 return $user_standings if $user_standings;
1099 return $user_standings =
1100 $apputils->simple_scalar_request(
1102 "open-ils.cstore.direct.config.standing.search.atomic",
1103 { id => { "!=" => undef } }
1109 __PACKAGE__->register_method(
1110 method => "get_my_org_path",
1111 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1114 sub get_my_org_path {
1115 my( $self, $client, $auth, $org_id ) = @_;
1116 my $e = new_editor(authtoken=>$auth);
1117 return $e->event unless $e->checkauth;
1118 $org_id = $e->requestor->ws_ou unless defined $org_id;
1120 return $apputils->simple_scalar_request(
1122 "open-ils.storage.actor.org_unit.full_path.atomic",
1127 __PACKAGE__->register_method(
1128 method => "patron_adv_search",
1129 api_name => "open-ils.actor.patron.search.advanced" );
1130 sub patron_adv_search {
1131 my( $self, $client, $auth, $search_hash,
1132 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1134 my $e = new_editor(authtoken=>$auth);
1135 return $e->event unless $e->checkauth;
1136 return $e->event unless $e->allowed('VIEW_USER');
1137 return $U->storagereq(
1138 "open-ils.storage.actor.user.crazy_search", $search_hash,
1139 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1143 __PACKAGE__->register_method(
1144 method => "update_passwd",
1146 api_name => "open-ils.actor.user.password.update");
1148 __PACKAGE__->register_method(
1149 method => "update_passwd",
1150 api_name => "open-ils.actor.user.username.update");
1152 __PACKAGE__->register_method(
1153 method => "update_passwd",
1154 api_name => "open-ils.actor.user.email.update");
1157 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1158 my $e = new_editor(xact=>1, authtoken=>$auth);
1159 return $e->die_event unless $e->checkauth;
1161 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1162 or return $e->die_event;
1163 my $api = $self->api_name;
1165 if( $api =~ /password/o ) {
1167 # make sure the original password matches the in-database password
1168 return OpenILS::Event->new('INCORRECT_PASSWORD')
1169 if md5_hex($orig_pw) ne $db_user->passwd;
1170 $db_user->passwd($new_val);
1174 # if we don't clear the password, the user will be updated with
1175 # a hashed version of the hashed version of their password
1176 $db_user->clear_passwd;
1178 if( $api =~ /username/o ) {
1180 # make sure no one else has this username
1181 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1182 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1183 $db_user->usrname($new_val);
1185 } elsif( $api =~ /email/o ) {
1186 $db_user->email($new_val);
1190 $e->update_actor_user($db_user) or return $e->die_event;
1198 __PACKAGE__->register_method(
1199 method => "check_user_perms",
1200 api_name => "open-ils.actor.user.perm.check",
1201 notes => <<" NOTES");
1202 Takes a login session, user id, an org id, and an array of perm type strings. For each
1203 perm type, if the user does *not* have the given permission it is added
1204 to a list which is returned from the method. If all permissions
1205 are allowed, an empty list is returned
1206 if the logged in user does not match 'user_id', then the logged in user must
1207 have VIEW_PERMISSION priveleges.
1210 sub check_user_perms {
1211 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1213 my( $staff, $evt ) = $apputils->checkses($login_session);
1214 return $evt if $evt;
1216 if($staff->id ne $user_id) {
1217 if( $evt = $apputils->check_perms(
1218 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1224 for my $perm (@$perm_types) {
1225 if($apputils->check_perms($user_id, $org_id, $perm)) {
1226 push @not_allowed, $perm;
1230 return \@not_allowed
1233 __PACKAGE__->register_method(
1234 method => "check_user_perms2",
1235 api_name => "open-ils.actor.user.perm.check.multi_org",
1237 Checks the permissions on a list of perms and orgs for a user
1238 @param authtoken The login session key
1239 @param user_id The id of the user to check
1240 @param orgs The array of org ids
1241 @param perms The array of permission names
1242 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1243 if the logged in user does not match 'user_id', then the logged in user must
1244 have VIEW_PERMISSION priveleges.
1247 sub check_user_perms2 {
1248 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1250 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1251 $authtoken, $user_id, 'VIEW_PERMISSION' );
1252 return $evt if $evt;
1255 for my $org (@$orgs) {
1256 for my $perm (@$perms) {
1257 if($apputils->check_perms($user_id, $org, $perm)) {
1258 push @not_allowed, [ $org, $perm ];
1263 return \@not_allowed
1267 __PACKAGE__->register_method(
1268 method => 'check_user_perms3',
1269 api_name => 'open-ils.actor.user.perm.highest_org',
1271 Returns the highest org unit id at which a user has a given permission
1272 If the requestor does not match the target user, the requestor must have
1273 'VIEW_PERMISSION' rights at the home org unit of the target user
1274 @param authtoken The login session key
1275 @param userid The id of the user in question
1276 @param perm The permission to check
1277 @return The org unit highest in the org tree within which the user has
1278 the requested permission
1281 sub check_user_perms3 {
1282 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1284 my( $staff, $target, $org, $evt );
1286 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1287 $authtoken, $userid, 'VIEW_PERMISSION' );
1288 return $evt if $evt;
1290 my $tree = $U->get_org_tree();
1291 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1295 __PACKAGE__->register_method(
1296 method => 'check_user_work_perms',
1297 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1301 Returns a set of org units which represent the highest orgs in
1302 the org tree where the user has the requested permission. The
1303 purpose of this method is to return the smallest set of org units
1304 which represent the full expanse of the user's ability to perform
1305 the requested action. The user whose perms this method should
1306 check is implied by the authtoken. /,
1308 {desc => 'authtoken', type => 'string'},
1309 {desc => 'permission name', type => 'string'},
1310 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1312 return => {desc => 'An array of org IDs'}
1316 __PACKAGE__->register_method(
1317 method => 'check_user_work_perms',
1318 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1321 @see open-ils.actor.user.work_perm.highest_org_set
1322 Returns a list of org trees. The root of each tree
1323 is the highest org in the organization hierarchy where the user has the
1324 requested permission. Below each tree root is its full tree of descendants.
1328 __PACKAGE__->register_method(
1329 method => 'check_user_work_perms',
1330 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1333 @see open-ils.actor.user.work_perm.highest_org_set
1334 Returns a list of list of all of the org_units where the user
1335 has the requested permission. The first item in each list
1336 is the highest permission org for that section of the
1337 org tree. The remaining items in each sub-list are the
1338 descendants of that org.
1343 __PACKAGE__->register_method(
1344 method => 'check_user_work_perms',
1345 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1348 @see open-ils.actor.user.work_perm.highest_org_set
1349 Returns a list of lists of all of the org_unit IDs where the user
1350 has the requested permission. The first item in each list
1351 is the highest permission org for that section of the
1352 org tree. The remaining items in each sub-list are the
1353 descendants of that org.
1357 sub check_user_work_perms {
1358 my($self, $conn, $auth, $perm, $options) = @_;
1359 my $e = new_editor(authtoken=>$auth);
1360 return $e->event unless $e->checkauth;
1361 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1363 return $orglist if $self->api_name =~ /highest_org_set/;
1365 # build a list of org trees
1366 return get_org_descendants($self, $conn, $orglist)
1367 if $self->api_name =~ /org_tree_list/;
1370 for my $orgid (@$orglist) {
1371 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1372 unshift @sublist, $orgid; # make sure it's at the front of the list
1373 if($self->api_name =~ /org_id_list/) {
1374 push(@list, @sublist);
1376 push(@list, @{$e->batch_retrieve_actor_org_unit(\@sublist)});
1384 __PACKAGE__->register_method(
1385 method => 'check_user_perms4',
1386 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1388 Returns the highest org unit id at which a user has a given permission
1389 If the requestor does not match the target user, the requestor must have
1390 'VIEW_PERMISSION' rights at the home org unit of the target user
1391 @param authtoken The login session key
1392 @param userid The id of the user in question
1393 @param perms An array of perm names to check
1394 @return An array of orgId's representing the org unit
1395 highest in the org tree within which the user has the requested permission
1396 The arrah of orgId's has matches the order of the perms array
1399 sub check_user_perms4 {
1400 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1402 my( $staff, $target, $org, $evt );
1404 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1405 $authtoken, $userid, 'VIEW_PERMISSION' );
1406 return $evt if $evt;
1409 return [] unless ref($perms);
1410 my $tree = $U->get_org_tree();
1412 for my $p (@$perms) {
1413 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1421 __PACKAGE__->register_method(
1422 method => "user_fines_summary",
1423 api_name => "open-ils.actor.user.fines.summary",
1425 notes => <<" NOTES");
1426 Returns a short summary of the users total open fines, excluding voided fines
1427 Params are login_session, user_id
1428 Returns a 'mous' object.
1431 sub user_fines_summary {
1432 my( $self, $client, $auth, $user_id ) = @_;
1433 my $e = new_editor(authtoken=>$auth);
1434 return $e->event unless $e->checkauth;
1435 my $user = $e->retrieve_actor_user($user_id)
1436 or return $e->event;
1438 if( $user_id ne $e->requestor->id ) {
1439 return $e->event unless
1440 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1443 # run this inside a transaction to prevent replication delay errors
1444 my $ses = $U->start_db_session();
1445 my $s = $ses->request(
1446 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1447 $U->rollback_db_session($ses);
1454 __PACKAGE__->register_method(
1455 method => "user_transactions",
1456 api_name => "open-ils.actor.user.transactions",
1457 notes => <<" NOTES");
1458 Returns a list of open user transactions (mbts objects);
1459 Params are login_session, user_id
1460 Optional third parameter is the transactions type. defaults to all
1463 __PACKAGE__->register_method(
1464 method => "user_transactions",
1465 api_name => "open-ils.actor.user.transactions.have_charge",
1466 notes => <<" NOTES");
1467 Returns a list of all open user transactions (mbts objects) that have an initial charge
1468 Params are login_session, user_id
1469 Optional third parameter is the transactions type. defaults to all
1472 __PACKAGE__->register_method(
1473 method => "user_transactions",
1474 api_name => "open-ils.actor.user.transactions.have_balance",
1475 notes => <<" NOTES");
1476 Returns a list of all open user transactions (mbts objects) that have a balance
1477 Params are login_session, user_id
1478 Optional third parameter is the transactions type. defaults to all
1481 __PACKAGE__->register_method(
1482 method => "user_transactions",
1483 api_name => "open-ils.actor.user.transactions.fleshed",
1484 notes => <<" NOTES");
1485 Returns an object/hash of transaction, circ, title where transaction = an open
1486 user transactions (mbts objects), circ is the attached circluation, and title
1487 is the title the circ points to
1488 Params are login_session, user_id
1489 Optional third parameter is the transactions type. defaults to all
1492 __PACKAGE__->register_method(
1493 method => "user_transactions",
1494 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1495 notes => <<" NOTES");
1496 Returns an object/hash of transaction, circ, title where transaction = an open
1497 user transactions that has an initial charge (mbts objects), circ is the
1498 attached circluation, and title is the title the circ points to
1499 Params are login_session, user_id
1500 Optional third parameter is the transactions type. defaults to all
1503 __PACKAGE__->register_method(
1504 method => "user_transactions",
1505 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1506 notes => <<" NOTES");
1507 Returns an object/hash of transaction, circ, title where transaction = an open
1508 user transaction that has a balance (mbts objects), circ is the attached
1509 circluation, and title is the title the circ points to
1510 Params are login_session, user_id
1511 Optional third parameter is the transaction type. defaults to all
1514 __PACKAGE__->register_method(
1515 method => "user_transactions",
1516 api_name => "open-ils.actor.user.transactions.count",
1517 notes => <<" NOTES");
1518 Returns an object/hash of transaction, circ, title where transaction = an open
1519 user transactions (mbts objects), circ is the attached circluation, and title
1520 is the title the circ points to
1521 Params are login_session, user_id
1522 Optional third parameter is the transactions type. defaults to all
1525 __PACKAGE__->register_method(
1526 method => "user_transactions",
1527 api_name => "open-ils.actor.user.transactions.have_charge.count",
1528 notes => <<" NOTES");
1529 Returns an object/hash of transaction, circ, title where transaction = an open
1530 user transactions that has an initial charge (mbts objects), circ is the
1531 attached circluation, and title is the title the circ points to
1532 Params are login_session, user_id
1533 Optional third parameter is the transactions type. defaults to all
1536 __PACKAGE__->register_method(
1537 method => "user_transactions",
1538 api_name => "open-ils.actor.user.transactions.have_balance.count",
1539 notes => <<" NOTES");
1540 Returns an object/hash of transaction, circ, title where transaction = an open
1541 user transaction that has a balance (mbts objects), circ is the attached
1542 circluation, and title is the title the circ points to
1543 Params are login_session, user_id
1544 Optional third parameter is the transaction type. defaults to all
1547 __PACKAGE__->register_method(
1548 method => "user_transactions",
1549 api_name => "open-ils.actor.user.transactions.have_balance.total",
1550 notes => <<" NOTES");
1551 Returns an object/hash of transaction, circ, title where transaction = an open
1552 user transaction that has a balance (mbts objects), circ is the attached
1553 circluation, and title is the title the circ points to
1554 Params are login_session, user_id
1555 Optional third parameter is the transaction type. defaults to all
1560 sub user_transactions {
1561 my( $self, $client, $login_session, $user_id, $type ) = @_;
1563 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1564 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1565 return $evt if $evt;
1567 my $api = $self->api_name();
1571 if(defined($type)) { @xact = (xact_type => $type);
1573 } else { @xact = (); }
1576 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1577 ->run($login_session => $user_id => $type);
1579 if($api =~ /have_charge/o) {
1581 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1583 } elsif($api =~ /have_balance/o) {
1585 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1588 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1592 if($api =~ /total/o) {
1594 for my $t (@$trans) {
1595 $total += $t->balance_owed;
1598 $logger->debug("Total balance owed by user $user_id: $total");
1602 if($api =~ /count/o) { return scalar @$trans; }
1603 if($api !~ /fleshed/o) { return $trans; }
1606 for my $t (@$trans) {
1608 if( $t->xact_type ne 'circulation' ) {
1609 push @resp, {transaction => $t};
1613 my $circ = $apputils->simple_scalar_request(
1615 "open-ils.cstore.direct.action.circulation.retrieve",
1620 my $title = $apputils->simple_scalar_request(
1622 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1623 $circ->target_copy );
1627 my $u = OpenILS::Utils::ModsParser->new();
1628 $u->start_mods_batch($title->marc());
1629 my $mods = $u->finish_mods_batch();
1630 $mods->doc_id($title->id) if $mods;
1632 push @resp, {transaction => $t, circ => $circ, record => $mods };
1640 __PACKAGE__->register_method(
1641 method => "user_transaction_retrieve",
1642 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1644 notes => <<" NOTES");
1645 Returns a fleshedtransaction record
1647 __PACKAGE__->register_method(
1648 method => "user_transaction_retrieve",
1649 api_name => "open-ils.actor.user.transaction.retrieve",
1651 notes => <<" NOTES");
1652 Returns a transaction record
1654 sub user_transaction_retrieve {
1655 my( $self, $client, $login_session, $bill_id ) = @_;
1657 # XXX I think I'm deprecated... make sure
1659 my $trans = $apputils->simple_scalar_request(
1661 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1665 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1666 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1667 return $evt if $evt;
1669 my $api = $self->api_name();
1670 if($api !~ /fleshed/o) { return $trans; }
1672 if( $trans->xact_type ne 'circulation' ) {
1673 $logger->debug("Returning non-circ transaction");
1674 return {transaction => $trans};
1677 my $circ = $apputils->simple_scalar_request(
1679 "open-ils..direct.action.circulation.retrieve",
1682 return {transaction => $trans} unless $circ;
1683 $logger->debug("Found the circ transaction");
1685 my $title = $apputils->simple_scalar_request(
1687 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1688 $circ->target_copy );
1690 return {transaction => $trans, circ => $circ } unless $title;
1691 $logger->debug("Found the circ title");
1695 my $u = OpenILS::Utils::ModsParser->new();
1696 $u->start_mods_batch($title->marc());
1697 $mods = $u->finish_mods_batch();
1699 if ($title->id == OILS_PRECAT_RECORD) {
1700 my $copy = $apputils->simple_scalar_request(
1702 "open-ils.cstore.direct.asset.copy.retrieve",
1703 $circ->target_copy );
1705 $mods = new Fieldmapper::metabib::virtual_record;
1706 $mods->doc_id(OILS_PRECAT_RECORD);
1707 $mods->title($copy->dummy_title);
1708 $mods->author($copy->dummy_author);
1712 $logger->debug("MODSized the circ title");
1714 return {transaction => $trans, circ => $circ, record => $mods };
1718 __PACKAGE__->register_method(
1719 method => "hold_request_count",
1720 api_name => "open-ils.actor.user.hold_requests.count",
1723 notes => <<" NOTES");
1724 Returns hold ready/total counts
1726 sub hold_request_count {
1727 my( $self, $client, $login_session, $userid ) = @_;
1729 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1730 $login_session, $userid, 'VIEW_HOLD' );
1731 return $evt if $evt;
1734 my $holds = $apputils->simple_scalar_request(
1736 "open-ils.cstore.direct.action.hold_request.search.atomic",
1739 fulfillment_time => {"=" => undef },
1740 cancel_time => undef,
1745 for my $h (@$holds) {
1746 next unless $h->capture_time and $h->current_copy;
1748 my $copy = $apputils->simple_scalar_request(
1750 "open-ils.cstore.direct.asset.copy.retrieve",
1754 if ($copy and $copy->status == 8) {
1759 return { total => scalar(@$holds), ready => scalar(@ready) };
1763 __PACKAGE__->register_method(
1764 method => "checkedout_count",
1765 api_name => "open-ils.actor.user.checked_out.count__",
1767 notes => <<" NOTES");
1768 Returns a transaction record
1772 sub checkedout_count {
1773 my( $self, $client, $login_session, $userid ) = @_;
1775 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1776 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1777 return $evt if $evt;
1779 my $circs = $apputils->simple_scalar_request(
1781 "open-ils.cstore.direct.action.circulation.search.atomic",
1782 { usr => $userid, stop_fines => undef }
1783 #{ usr => $userid, checkin_time => {"=" => undef } }
1786 my $parser = DateTime::Format::ISO8601->new;
1789 for my $c (@$circs) {
1790 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1791 my $due = $due_dt->epoch;
1793 if ($due < DateTime->today->epoch) {
1798 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1802 __PACKAGE__->register_method(
1803 method => "checked_out",
1804 api_name => "open-ils.actor.user.checked_out",
1808 Returns a structure of circulations objects sorted by
1809 out, overdue, lost, claims_returned, long_overdue.
1810 A list of IDs are returned of each type.
1811 lost, long_overdue, and claims_returned circ will not
1812 be "finished" (there is an outstanding balance or some
1813 other pending action on the circ).
1815 The .count method also includes a 'total' field which
1816 sums all "open" circs
1820 __PACKAGE__->register_method(
1821 method => "checked_out",
1822 api_name => "open-ils.actor.user.checked_out.count",
1825 signature => q/@see open-ils.actor.user.checked_out/
1829 my( $self, $conn, $auth, $userid ) = @_;
1831 my $e = new_editor(authtoken=>$auth);
1832 return $e->event unless $e->checkauth;
1834 if( $userid ne $e->requestor->id ) {
1835 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1838 my $count = $self->api_name =~ /count/;
1839 return _checked_out( $count, $e, $userid );
1843 my( $iscount, $e, $userid ) = @_;
1846 my $meth = 'open-ils.storage.actor.user.checked_out';
1847 $meth = "$meth.count" if $iscount;
1848 return $U->storagereq($meth, $userid);
1850 # XXX Old code - moved to storage
1851 #------------------------------------------------------------------------------
1852 #------------------------------------------------------------------------------
1853 my $circs = $e->search_action_circulation(
1854 { usr => $userid, checkin_time => undef });
1856 my $parser = DateTime::Format::ISO8601->new;
1858 # split the circs up into overdue and not-overdue circs
1860 for my $c (@$circs) {
1861 if( $c->due_date ) {
1862 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1863 my $due = $due_dt->epoch;
1864 if ($due < DateTime->today->epoch) {
1874 my( @open, @od, @lost, @cr, @lo );
1876 while (my $c = shift(@out)) {
1877 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1878 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1879 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1880 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1883 while (my $c = shift(@overdue)) {
1884 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1885 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1886 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1887 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1892 total => @open + @od + @lost + @cr + @lo,
1893 out => scalar(@open),
1894 overdue => scalar(@od),
1895 lost => scalar(@lost),
1896 claims_returned => scalar(@cr),
1897 long_overdue => scalar(@lo)
1905 claims_returned => \@cr,
1906 long_overdue => \@lo
1911 sub _checked_out_WHAT {
1912 my( $iscount, $e, $userid ) = @_;
1914 my $circs = $e->search_action_circulation(
1915 { usr => $userid, stop_fines => undef });
1917 my $mcircs = $e->search_action_circulation(
1920 checkin_time => undef,
1921 xact_finish => undef,
1925 push( @$circs, @$mcircs );
1927 my $parser = DateTime::Format::ISO8601->new;
1929 # split the circs up into overdue and not-overdue circs
1931 for my $c (@$circs) {
1932 if( $c->due_date ) {
1933 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1934 my $due = $due_dt->epoch;
1935 if ($due < DateTime->today->epoch) {
1936 push @overdue, $c->id;
1945 # grab all of the lost, claims-returned, and longoverdue circs
1946 #my $open = $e->search_action_circulation(
1947 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1950 # these items have stop_fines, but no xact_finish, so money
1951 # is owed on them and they have not been checked in
1952 my $open = $e->search_action_circulation(
1955 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1956 xact_finish => undef,
1957 checkin_time => undef,
1962 my( @lost, @cr, @lo );
1963 for my $c (@$open) {
1964 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1965 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1966 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1972 total => @$circs + @lost + @cr + @lo,
1973 out => scalar(@out),
1974 overdue => scalar(@overdue),
1975 lost => scalar(@lost),
1976 claims_returned => scalar(@cr),
1977 long_overdue => scalar(@lo)
1983 overdue => \@overdue,
1985 claims_returned => \@cr,
1986 long_overdue => \@lo
1992 __PACKAGE__->register_method(
1993 method => "checked_in_with_fines",
1994 api_name => "open-ils.actor.user.checked_in_with_fines",
1997 signature => q/@see open-ils.actor.user.checked_out/
1999 sub checked_in_with_fines {
2000 my( $self, $conn, $auth, $userid ) = @_;
2002 my $e = new_editor(authtoken=>$auth);
2003 return $e->event unless $e->checkauth;
2005 if( $userid ne $e->requestor->id ) {
2006 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2009 # money is owed on these items and they are checked in
2010 my $open = $e->search_action_circulation(
2013 xact_finish => undef,
2014 checkin_time => { "!=" => undef },
2019 my( @lost, @cr, @lo );
2020 for my $c (@$open) {
2021 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2022 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2023 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2028 claims_returned => \@cr,
2029 long_overdue => \@lo
2041 __PACKAGE__->register_method(
2042 method => "user_transaction_history",
2043 api_name => "open-ils.actor.user.transactions.history",
2045 notes => <<" NOTES");
2046 Returns a list of billable transaction ids for a user, optionally by type
2048 __PACKAGE__->register_method(
2049 method => "user_transaction_history",
2050 api_name => "open-ils.actor.user.transactions.history.have_charge",
2052 notes => <<" NOTES");
2053 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2055 __PACKAGE__->register_method(
2056 method => "user_transaction_history",
2057 api_name => "open-ils.actor.user.transactions.history.have_balance",
2060 notes => <<" NOTES");
2061 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2063 __PACKAGE__->register_method(
2064 method => "user_transaction_history",
2065 api_name => "open-ils.actor.user.transactions.history.still_open",
2067 notes => <<" NOTES");
2068 Returns a list of billable transaction ids for a user that are not finished
2070 __PACKAGE__->register_method(
2071 method => "user_transaction_history",
2072 api_name => "open-ils.actor.user.transactions.history.have_bill",
2075 notes => <<" NOTES");
2076 Returns a list of billable transaction ids for a user that has billings
2082 sub _user_transaction_history {
2083 my( $self, $client, $login_session, $user_id, $type ) = @_;
2085 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2086 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2087 return $evt if $evt;
2089 my $api = $self->api_name();
2094 @xact = (xact_type => $type) if(defined($type));
2095 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2096 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2098 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2100 my $trans = $apputils->simple_scalar_request(
2102 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2103 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2105 return [ map { $_->id } @$trans ];
2109 =head SEE APPUTILS.PM
2114 for my $x (@xacts) {
2115 my $s = new Fieldmapper::money::billable_transaction_summary;
2118 $s->xact_start( $x->xact_start );
2119 $s->xact_finish( $x->xact_finish );
2123 for my $b (@{ $x->billings }) {
2124 next if ($U->is_true($b->voided));
2125 $to += ($b->amount * 100);
2126 $lb ||= $b->billing_ts;
2127 if ($b->billing_ts ge $lb) {
2128 $lb = $b->billing_ts;
2129 $s->last_billing_note($b->note);
2130 $s->last_billing_ts($b->billing_ts);
2131 $s->last_billing_type($b->billing_type);
2135 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2139 for my $p (@{ $x->payments }) {
2140 next if ($U->is_true($p->voided));
2141 $tp += ($p->amount * 100);
2142 $lp ||= $p->payment_ts;
2143 if ($p->payment_ts ge $lp) {
2144 $lp = $p->payment_ts;
2145 $s->last_payment_note($p->note);
2146 $s->last_payment_ts($p->payment_ts);
2147 $s->last_payment_type($p->payment_type);
2150 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2152 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2154 $s->xact_type( 'grocery' ) if ($x->grocery);
2155 $s->xact_type( 'circulation' ) if ($x->circulation);
2164 sub user_transaction_history {
2165 my( $self, $conn, $auth, $userid, $type ) = @_;
2167 # run inside of a transaction to prevent replication delays
2168 my $e = new_editor(xact=>1, authtoken=>$auth);
2169 return $e->die_event unless $e->checkauth;
2171 if( $e->requestor->id ne $userid ) {
2172 return $e->die_event
2173 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2176 my $api = $self->api_name;
2177 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2179 my @xacts = @{ $e->search_money_billable_transaction(
2180 [ { usr => $userid, @xact_finish },
2182 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2183 order_by => { mbt => 'xact_start DESC' },
2191 #my @mbts = _make_mbts( @xacts );
2192 my @mbts = $U->make_mbts( @xacts );
2194 if(defined($type)) {
2195 @mbts = grep { $_->xact_type eq $type } @mbts;
2198 if($api =~ /have_balance/o) {
2199 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2202 if($api =~ /have_charge/o) {
2203 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2206 if($api =~ /have_bill/o) {
2207 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2215 __PACKAGE__->register_method(
2216 method => "user_perms",
2217 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2219 notes => <<" NOTES");
2220 Returns a list of permissions
2223 my( $self, $client, $authtoken, $user ) = @_;
2225 my( $staff, $evt ) = $apputils->checkses($authtoken);
2226 return $evt if $evt;
2228 $user ||= $staff->id;
2230 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2234 return $apputils->simple_scalar_request(
2236 "open-ils.storage.permission.user_perms.atomic",
2240 __PACKAGE__->register_method(
2241 method => "retrieve_perms",
2242 api_name => "open-ils.actor.permissions.retrieve",
2243 notes => <<" NOTES");
2244 Returns a list of permissions
2246 sub retrieve_perms {
2247 my( $self, $client ) = @_;
2248 return $apputils->simple_scalar_request(
2250 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2251 { id => { '!=' => undef } }
2255 __PACKAGE__->register_method(
2256 method => "retrieve_groups",
2257 api_name => "open-ils.actor.groups.retrieve",
2258 notes => <<" NOTES");
2259 Returns a list of user groupss
2261 sub retrieve_groups {
2262 my( $self, $client ) = @_;
2263 return new_editor()->retrieve_all_permission_grp_tree();
2266 __PACKAGE__->register_method(
2267 method => "retrieve_org_address",
2268 api_name => "open-ils.actor.org_unit.address.retrieve",
2269 notes => <<' NOTES');
2270 Returns an org_unit address by ID
2271 @param An org_address ID
2273 sub retrieve_org_address {
2274 my( $self, $client, $id ) = @_;
2275 return $apputils->simple_scalar_request(
2277 "open-ils.cstore.direct.actor.org_address.retrieve",
2282 __PACKAGE__->register_method(
2283 method => "retrieve_groups_tree",
2284 api_name => "open-ils.actor.groups.tree.retrieve",
2285 notes => <<" NOTES");
2286 Returns a list of user groups
2288 sub retrieve_groups_tree {
2289 my( $self, $client ) = @_;
2290 return new_editor()->search_permission_grp_tree(
2295 flesh_fields => { pgt => ["children"] },
2296 order_by => { pgt => 'name'}
2303 # turns an org list into an org tree
2305 sub build_group_tree {
2307 my( $self, $grplist) = @_;
2309 return $grplist unless (
2310 ref($grplist) and @$grplist > 1 );
2312 my @list = sort { $a->name cmp $b->name } @$grplist;
2315 for my $grp (@list) {
2317 if ($grp and !defined($grp->parent)) {
2321 my ($parent) = grep { $_->id == $grp->parent} @list;
2323 $parent->children([]) unless defined($parent->children);
2324 push( @{$parent->children}, $grp );
2332 __PACKAGE__->register_method(
2333 method => "add_user_to_groups",
2334 api_name => "open-ils.actor.user.set_groups",
2335 notes => <<" NOTES");
2336 Adds a user to one or more permission groups
2339 sub add_user_to_groups {
2340 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2342 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2343 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2344 return $evt if $evt;
2346 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2347 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2348 return $evt if $evt;
2350 $apputils->simplereq(
2352 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2354 for my $group (@$groups) {
2355 my $link = Fieldmapper::permission::usr_grp_map->new;
2357 $link->usr($userid);
2359 my $id = $apputils->simplereq(
2361 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2367 __PACKAGE__->register_method(
2368 method => "get_user_perm_groups",
2369 api_name => "open-ils.actor.user.get_groups",
2370 notes => <<" NOTES");
2371 Retrieve a user's permission groups.
2375 sub get_user_perm_groups {
2376 my( $self, $client, $authtoken, $userid ) = @_;
2378 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2379 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2380 return $evt if $evt;
2382 return $apputils->simplereq(
2384 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2388 __PACKAGE__->register_method(
2389 method => "get_user_work_ous",
2390 api_name => "open-ils.actor.user.get_work_ous",
2391 notes => <<" NOTES");
2392 Retrieve a user's work org units.
2394 __PACKAGE__->register_method(
2395 method => "get_user_work_ous",
2396 api_name => "open-ils.actor.user.get_work_ous.ids",
2397 notes => <<" NOTES");
2398 Retrieve a user's work org units.
2402 sub get_user_work_ous {
2403 my( $self, $client, $auth, $userid ) = @_;
2404 my $e = new_editor(authtoken=>$auth);
2405 return $e->event unless $e->checkauth;
2406 $userid ||= $e->requestor->id;
2408 if($e->requestor->id != $userid) {
2409 my $user = $e->retrieve_actor_user($userid)
2410 or return $e->event;
2411 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2414 return $e->search_permission_usr_work_ou_map({usr => $userid})
2415 unless $self->api_name =~ /.ids$/;
2417 # client just wants a list of org IDs
2418 return $U->get_user_work_ou_ids($e, $userid);
2424 __PACKAGE__->register_method (
2425 method => 'register_workstation',
2426 api_name => 'open-ils.actor.workstation.register.override',
2427 signature => q/@see open-ils.actor.workstation.register/);
2429 __PACKAGE__->register_method (
2430 method => 'register_workstation',
2431 api_name => 'open-ils.actor.workstation.register',
2433 Registers a new workstion in the system
2434 @param authtoken The login session key
2435 @param name The name of the workstation id
2436 @param owner The org unit that owns this workstation
2437 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2438 if the name is already in use.
2441 sub register_workstation {
2442 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2444 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2445 return $e->die_event unless $e->checkauth;
2446 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2447 my $existing = $e->search_actor_workstation({name => $name})->[0];
2451 if( $self->api_name =~ /override/o ) {
2452 # workstation with the given name exists.
2454 if($owner ne $existing->owning_lib) {
2455 # if necessary, update the owning_lib of the workstation
2457 $logger->info("changing owning lib of workstation ".$existing->id.
2458 " from ".$existing->owning_lib." to $owner");
2459 return $e->die_event unless
2460 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2462 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2464 $existing->owning_lib($owner);
2465 return $e->die_event unless $e->update_actor_workstation($existing);
2471 "attempt to register an existing workstation. returning existing ID");
2474 return $existing->id;
2477 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2481 my $ws = Fieldmapper::actor::workstation->new;
2482 $ws->owning_lib($owner);
2484 $e->create_actor_workstation($ws) or return $e->die_event;
2486 return $ws->id; # note: editor sets the id on the new object for us
2489 __PACKAGE__->register_method (
2490 method => 'workstation_list',
2491 api_name => 'open-ils.actor.workstation.list',
2493 Returns a list of workstations registered at the given location
2494 @param authtoken The login session key
2495 @param ids A list of org_unit.id's for the workstation owners
2498 sub workstation_list {
2499 my( $self, $conn, $authtoken, @orgs ) = @_;
2501 my $e = new_editor(authtoken=>$authtoken);
2502 return $e->event unless $e->checkauth;
2507 unless $e->allowed('REGISTER_WORKSTATION', $o);
2508 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2519 __PACKAGE__->register_method (
2520 method => 'fetch_patron_note',
2521 api_name => 'open-ils.actor.note.retrieve.all',
2524 Returns a list of notes for a given user
2525 Requestor must have VIEW_USER permission if pub==false and
2526 @param authtoken The login session key
2527 @param args Hash of params including
2528 patronid : the patron's id
2529 pub : true if retrieving only public notes
2533 sub fetch_patron_note {
2534 my( $self, $conn, $authtoken, $args ) = @_;
2535 my $patronid = $$args{patronid};
2537 my($reqr, $evt) = $U->checkses($authtoken);
2538 return $evt if $evt;
2541 ($patron, $evt) = $U->fetch_user($patronid);
2542 return $evt if $evt;
2545 if( $patronid ne $reqr->id ) {
2546 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2547 return $evt if $evt;
2549 return $U->cstorereq(
2550 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2551 { usr => $patronid, pub => 't' } );
2554 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2555 return $evt if $evt;
2557 return $U->cstorereq(
2558 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2561 __PACKAGE__->register_method (
2562 method => 'create_user_note',
2563 api_name => 'open-ils.actor.note.create',
2565 Creates a new note for the given user
2566 @param authtoken The login session key
2567 @param note The note object
2570 sub create_user_note {
2571 my( $self, $conn, $authtoken, $note ) = @_;
2572 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2573 return $e->die_event unless $e->checkauth;
2575 my $user = $e->retrieve_actor_user($note->usr)
2576 or return $e->die_event;
2578 return $e->die_event unless
2579 $e->allowed('UPDATE_USER',$user->home_ou);
2581 $note->creator($e->requestor->id);
2582 $e->create_actor_usr_note($note) or return $e->die_event;
2588 __PACKAGE__->register_method (
2589 method => 'delete_user_note',
2590 api_name => 'open-ils.actor.note.delete',
2592 Deletes a note for the given user
2593 @param authtoken The login session key
2594 @param noteid The note id
2597 sub delete_user_note {
2598 my( $self, $conn, $authtoken, $noteid ) = @_;
2600 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2601 return $e->die_event unless $e->checkauth;
2602 my $note = $e->retrieve_actor_usr_note($noteid)
2603 or return $e->die_event;
2604 my $user = $e->retrieve_actor_user($note->usr)
2605 or return $e->die_event;
2606 return $e->die_event unless
2607 $e->allowed('UPDATE_USER', $user->home_ou);
2609 $e->delete_actor_usr_note($note) or return $e->die_event;
2615 __PACKAGE__->register_method (
2616 method => 'update_user_note',
2617 api_name => 'open-ils.actor.note.update',
2619 @param authtoken The login session key
2620 @param note The note
2624 sub update_user_note {
2625 my( $self, $conn, $auth, $note ) = @_;
2626 my $e = new_editor(authtoken=>$auth, xact=>1);
2627 return $e->event unless $e->checkauth;
2628 my $patron = $e->retrieve_actor_user($note->usr)
2629 or return $e->event;
2630 return $e->event unless
2631 $e->allowed('UPDATE_USER', $patron->home_ou);
2632 $e->update_actor_user_note($note)
2633 or return $e->event;
2641 __PACKAGE__->register_method (
2642 method => 'create_closed_date',
2643 api_name => 'open-ils.actor.org_unit.closed_date.create',
2645 Creates a new closing entry for the given org_unit
2646 @param authtoken The login session key
2647 @param note The closed_date object
2650 sub create_closed_date {
2651 my( $self, $conn, $authtoken, $cd ) = @_;
2653 my( $user, $evt ) = $U->checkses($authtoken);
2654 return $evt if $evt;
2656 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2657 return $evt if $evt;
2659 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2661 my $id = $U->storagereq(
2662 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2663 return $U->DB_UPDATE_FAILED($cd) unless $id;
2668 __PACKAGE__->register_method (
2669 method => 'delete_closed_date',
2670 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2672 Deletes a closing entry for the given org_unit
2673 @param authtoken The login session key
2674 @param noteid The close_date id
2677 sub delete_closed_date {
2678 my( $self, $conn, $authtoken, $cd ) = @_;
2680 my( $user, $evt ) = $U->checkses($authtoken);
2681 return $evt if $evt;
2684 ($cd_obj, $evt) = fetch_closed_date($cd);
2685 return $evt if $evt;
2687 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2688 return $evt if $evt;
2690 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2692 my $stat = $U->storagereq(
2693 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2694 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2699 __PACKAGE__->register_method(
2700 method => 'usrname_exists',
2701 api_name => 'open-ils.actor.username.exists',
2703 Returns 1 if the requested username exists, returns 0 otherwise
2707 sub usrname_exists {
2708 my( $self, $conn, $auth, $usrname ) = @_;
2709 my $e = new_editor(authtoken=>$auth);
2710 return $e->event unless $e->checkauth;
2711 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2712 return $$a[0] if $a and @$a;
2716 __PACKAGE__->register_method(
2717 method => 'barcode_exists',
2718 api_name => 'open-ils.actor.barcode.exists',
2721 Returns 1 if the requested barcode exists, returns 0 otherwise
2725 sub barcode_exists {
2726 my( $self, $conn, $auth, $barcode ) = @_;
2727 my $e = new_editor(authtoken=>$auth);
2728 return $e->event unless $e->checkauth;
2729 my $card = $e->search_actor_card({barcode => $barcode});
2730 return undef unless @$card;
2731 return $card->[0]->usr;
2735 __PACKAGE__->register_method(
2736 method => 'retrieve_net_levels',
2737 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2740 sub retrieve_net_levels {
2741 my( $self, $conn, $auth ) = @_;
2742 my $e = new_editor(authtoken=>$auth);
2743 return $e->event unless $e->checkauth;
2744 return $e->retrieve_all_config_net_access_level();
2748 __PACKAGE__->register_method(
2749 method => 'fetch_org_by_shortname',
2750 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2752 sub fetch_org_by_shortname {
2753 my( $self, $conn, $sname ) = @_;
2754 my $e = new_editor();
2755 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2756 return $e->event unless $org;
2761 __PACKAGE__->register_method(
2762 method => 'session_home_lib',
2763 api_name => 'open-ils.actor.session.home_lib',
2766 sub session_home_lib {
2767 my( $self, $conn, $auth ) = @_;
2768 my $e = new_editor(authtoken=>$auth);
2769 return undef unless $e->checkauth;
2770 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2771 return $org->shortname;
2774 __PACKAGE__->register_method(
2775 method => 'session_safe_token',
2776 api_name => 'open-ils.actor.session.safe_token',
2778 Returns a hashed session ID that is safe for export to the world.
2779 This safe token will expire after 1 hour of non-use.
2780 @param auth Active authentication token
2784 sub session_safe_token {
2785 my( $self, $conn, $auth ) = @_;
2786 my $e = new_editor(authtoken=>$auth);
2787 return undef unless $e->checkauth;
2789 my $safe_token = md5_hex($auth);
2791 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2793 # Add more like the following if needed...
2795 "safe-token-home_lib-shortname-$safe_token",
2796 $e->retrieve_actor_org_unit(
2797 $e->requestor->home_ou
2806 __PACKAGE__->register_method(
2807 method => 'safe_token_home_lib',
2808 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2810 Returns the home library shortname from the session
2811 asscociated with a safe token from generated by
2812 open-ils.actor.session.safe_token.
2813 @param safe_token Active safe token
2817 sub safe_token_home_lib {
2818 my( $self, $conn, $safe_token ) = @_;
2820 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2821 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2826 __PACKAGE__->register_method(
2827 method => 'slim_tree',
2828 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2831 my $tree = new_editor()->search_actor_org_unit(
2833 {"parent_ou" => undef },
2836 flesh_fields => { aou => ['children'] },
2837 order_by => { aou => 'name'},
2838 select => { aou => ["id","shortname", "name"]},
2843 return trim_tree($tree);
2849 return undef unless $tree;
2851 code => $tree->shortname,
2852 name => $tree->name,
2854 if( $tree->children and @{$tree->children} ) {
2855 $htree->{children} = [];
2856 for my $c (@{$tree->children}) {
2857 push( @{$htree->{children}}, trim_tree($c) );
2865 __PACKAGE__->register_method(
2866 method => "update_penalties",
2867 api_name => "open-ils.actor.user.penalties.update");
2868 sub update_penalties {
2869 my( $self, $conn, $auth, $userid ) = @_;
2870 my $e = new_editor(authtoken=>$auth);
2871 return $e->event unless $e->checkauth;
2872 $U->update_patron_penalties(
2874 patronid => $userid,
2881 __PACKAGE__->register_method(
2882 method => "user_retrieve_fleshed_by_id",
2883 api_name => "open-ils.actor.user.fleshed.retrieve",);
2885 sub user_retrieve_fleshed_by_id {
2886 my( $self, $client, $auth, $user_id, $fields ) = @_;
2887 my $e = new_editor(authtoken => $auth);
2888 return $e->event unless $e->checkauth;
2890 if( $e->requestor->id != $user_id ) {
2891 return $e->event unless $e->allowed('VIEW_USER');
2897 "standing_penalties",
2901 "stat_cat_entries" ];
2902 return new_flesh_user($user_id, $fields, $e);
2906 sub new_flesh_user {
2909 my $fields = shift || [];
2910 my $e = shift || new_editor(xact=>1);
2912 my $user = $e->retrieve_actor_user(
2917 "flesh_fields" => { "au" => $fields }
2920 ) or return $e->event;
2923 if( grep { $_ eq 'addresses' } @$fields ) {
2925 $user->addresses([]) unless @{$user->addresses};
2927 if( ref $user->billing_address ) {
2928 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2929 push( @{$user->addresses}, $user->billing_address );
2933 if( ref $user->mailing_address ) {
2934 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2935 push( @{$user->addresses}, $user->mailing_address );
2941 $user->clear_passwd();
2948 __PACKAGE__->register_method(
2949 method => "user_retrieve_parts",
2950 api_name => "open-ils.actor.user.retrieve.parts",);
2952 sub user_retrieve_parts {
2953 my( $self, $client, $auth, $user_id, $fields ) = @_;
2954 my $e = new_editor(authtoken => $auth);
2955 return $e->event unless $e->checkauth;
2956 if( $e->requestor->id != $user_id ) {
2957 return $e->event unless $e->allowed('VIEW_USER');
2960 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2961 push(@resp, $user->$_()) for(@$fields);
2967 __PACKAGE__->register_method(
2968 method => 'user_opt_in_enabled',
2969 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2971 @return 1 if user opt-in is globally enabled, 0 otherwise.
2974 sub user_opt_in_enabled {
2975 my($self, $conn) = @_;
2976 my $sc = OpenSRF::Utils::SettingsClient->new;
2977 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2982 __PACKAGE__->register_method(
2983 method => 'user_opt_in_at_org',
2984 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2986 @param $auth The auth token
2987 @param user_id The ID of the user to test
2988 @return 1 if the user has opted in at the specified org,
2989 event on error, and 0 otherwise. /);
2990 sub user_opt_in_at_org {
2991 my($self, $conn, $auth, $user_id) = @_;
2993 # see if we even need to enforce the opt-in value
2994 return 1 unless user_opt_in_enabled($self);
2996 my $e = new_editor(authtoken => $auth);
2997 return $e->event unless $e->checkauth;
2998 my $org_id = $e->requestor->ws_ou;
3000 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3001 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3003 # user is automatically opted-in at the home org
3004 return 1 if $user->home_ou eq $org_id;
3006 my $vals = $e->search_actor_usr_org_unit_opt_in(
3007 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3013 __PACKAGE__->register_method(
3014 method => 'create_user_opt_in_at_org',
3015 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3017 @param $auth The auth token
3018 @param user_id The ID of the user to test
3019 @return The ID of the newly created object, event on error./);
3021 sub create_user_opt_in_at_org {
3022 my($self, $conn, $auth, $user_id) = @_;
3024 my $e = new_editor(authtoken => $auth, xact=>1);
3025 return $e->die_event unless $e->checkauth;
3026 my $org_id = $e->requestor->ws_ou;
3028 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3029 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3031 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3033 $opt_in->org_unit($org_id);
3034 $opt_in->usr($user_id);
3035 $opt_in->staff($e->requestor->id);
3036 $opt_in->opt_in_ts('now');
3037 $opt_in->opt_in_ws($e->requestor->wsid);
3039 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3040 or return $e->die_event;