1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
5 $Data::Dumper::Indent = 0;
8 use Digest::MD5 qw(md5_hex);
10 use OpenSRF::EX qw(:try);
13 use OpenILS::Application::AppUtils;
15 use OpenILS::Utils::Fieldmapper;
16 use OpenILS::Utils::ModsParser;
17 use OpenSRF::Utils::Logger qw/$logger/;
18 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::Cache;
24 use DateTime::Format::ISO8601;
25 use OpenILS::Const qw/:const/;
27 use OpenILS::Application::Actor::Container;
28 use OpenILS::Application::Actor::ClosedDates;
30 use OpenILS::Utils::CStoreEditor qw/:funcs/;
32 use OpenILS::Application::Actor::UserGroups;
34 OpenILS::Application::Actor::Container->initialize();
35 OpenILS::Application::Actor::UserGroups->initialize();
36 OpenILS::Application::Actor::ClosedDates->initialize();
39 my $apputils = "OpenILS::Application::AppUtils";
42 sub _d { warn "Patron:\n" . Dumper(shift()); }
47 my $set_user_settings;
50 __PACKAGE__->register_method(
51 method => "set_user_settings",
52 api_name => "open-ils.actor.patron.settings.update",
54 sub set_user_settings {
55 my( $self, $client, $user_session, $uid, $settings ) = @_;
57 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
59 my( $staff, $user, $evt ) =
60 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
64 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
66 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
68 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
70 my $ses = $U->start_db_session();
71 my $stat = $ses->request(
72 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
73 $U->commit_db_session($ses);
80 __PACKAGE__->register_method(
81 method => "set_ou_settings",
82 api_name => "open-ils.actor.org_unit.settings.update",
85 my( $self, $client, $user_session, $ouid, $settings ) = @_;
87 my( $staff, $evt ) = $apputils->checkses( $user_session );
89 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
93 for my $set (keys %$settings) {
95 my $json = JSON->perl2JSON($$settings{$set});
96 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
99 { org_unit => $ouid, name => $set },
100 { value => $json } );
103 my $ses = $U->start_db_session();
104 my $stat = $ses->request(
105 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
106 $U->commit_db_session($ses);
112 my $fetch_user_settings;
113 my $fetch_ou_settings;
115 __PACKAGE__->register_method(
116 method => "user_settings",
117 api_name => "open-ils.actor.patron.settings.retrieve",
120 my( $self, $client, $user_session, $uid, $setting ) = @_;
122 my( $staff, $user, $evt ) =
123 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
126 $logger->debug("User " . $staff->id . " fetching user $uid\n");
127 my $s = $apputils->simplereq(
129 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
131 my $settings = { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
133 return $$settings{$setting} if $setting;
139 __PACKAGE__->register_method(
140 method => "ou_settings",
141 api_name => "open-ils.actor.org_unit.settings.retrieve",
144 my( $self, $client, $ouid ) = @_;
146 $logger->info("Fetching org unit settings for org $ouid");
148 my $s = $apputils->simplereq(
150 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
152 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
157 __PACKAGE__->register_method(
158 api_name => 'open-ils.actor.ou_setting.ancestor_default',
159 method => 'ou_ancestor_setting',
162 # ------------------------------------------------------------------
163 # Attempts to find the org setting value for a given org. if not
164 # found at the requested org, searches up the org tree until it
165 # finds a parent that has the requested setting.
166 # when found, returns { org => $id, value => $value }
167 # otherwise, returns NULL
168 # ------------------------------------------------------------------
169 sub ou_ancestor_setting {
170 my( $self, $client, $orgid, $name ) = @_;
171 return $U->ou_ancestor_setting($orgid, $name);
177 __PACKAGE__->register_method (
178 method => "ou_setting_delete",
179 api_name => 'open-ils.actor.org_setting.delete',
181 Deletes a specific org unit setting for a specific location
182 @param authtoken The login session key
183 @param orgid The org unit whose setting we're changing
184 @param setting The name of the setting to delete
185 @return True value on success.
189 sub ou_setting_delete {
190 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
191 my( $reqr, $evt) = $U->checkses($authtoken);
193 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
196 my $id = $U->cstorereq(
197 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
198 { name => $setting, org_unit => $orgid } );
200 $logger->debug("Retrieved setting $id in org unit setting delete");
202 my $s = $U->cstorereq(
203 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
205 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
219 __PACKAGE__->register_method(
220 method => "update_patron",
221 api_name => "open-ils.actor.patron.update",);
224 my( $self, $client, $user_session, $patron ) = @_;
226 my $session = $apputils->start_db_session();
230 $logger->info("Creating new patron...") if $patron->isnew;
231 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
233 my( $user_obj, $evt ) = $U->checkses($user_session);
236 $evt = check_group_perm($session, $user_obj, $patron);
240 # $new_patron is the patron in progress. $patron is the original patron
241 # passed in with the method. new_patron will change as the components
242 # of patron are added/updated.
246 # unflesh the real items on the patron
247 $patron->card( $patron->card->id ) if(ref($patron->card));
248 $patron->billing_address( $patron->billing_address->id )
249 if(ref($patron->billing_address));
250 $patron->mailing_address( $patron->mailing_address->id )
251 if(ref($patron->mailing_address));
253 # create/update the patron first so we can use his id
254 if($patron->isnew()) {
255 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
257 } else { $new_patron = $patron; }
259 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
262 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
265 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
268 # re-update the patron if anything has happened to him during this process
269 if($new_patron->ischanged()) {
270 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
274 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
277 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
280 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
283 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
286 if(!$patron->isnew) {
287 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
290 $apputils->commit_db_session($session);
291 my $fuser = flesh_user($new_patron->id());
294 # Log the new and old patron for investigation
295 $logger->info("$user_session updating patron object. orig patron object = ".
296 JSON->perl2JSON($opatron). " |||| new patron = ".JSON->perl2JSON($fuser));
306 return new_flesh_user($id, [
309 "standing_penalties",
313 "stat_cat_entries" ] );
321 # clone and clear stuff that would break the database
325 my $new_patron = $patron->clone;
327 $new_patron->clear_billing_address();
328 $new_patron->clear_mailing_address();
329 $new_patron->clear_addresses();
330 $new_patron->clear_card();
331 $new_patron->clear_cards();
332 $new_patron->clear_id();
333 $new_patron->clear_isnew();
334 $new_patron->clear_ischanged();
335 $new_patron->clear_isdeleted();
336 $new_patron->clear_stat_cat_entries();
337 $new_patron->clear_permissions();
338 $new_patron->clear_standing_penalties();
348 my $user_obj = shift;
350 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
351 return (undef, $evt) if $evt;
353 my $ex = $session->request(
354 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
356 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
359 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
361 my $id = $session->request(
362 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
363 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
365 $logger->info("Successfully created new user [$id] in DB");
367 return ( $session->request(
368 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
372 sub check_group_perm {
373 my( $session, $requestor, $patron ) = @_;
376 # first let's see if the requestor has
377 # priveleges to update this user in any way
378 if( ! $patron->isnew ) {
379 my $p = $session->request(
380 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
382 # If we are the requestor (trying to update our own account)
383 # and we are not trying to change our profile, we're good
384 if( $p->id == $requestor->id and
385 $p->profile == $patron->profile ) {
390 $evt = group_perm_failed($session, $requestor, $p);
394 # They are allowed to edit this patron.. can they put the
395 # patron into the group requested?
396 $evt = group_perm_failed($session, $requestor, $patron);
402 sub group_perm_failed {
403 my( $session, $requestor, $patron ) = @_;
407 my $grpid = $patron->profile;
411 $logger->debug("user update looking for group perm for group $grpid");
412 $grp = $session->request(
413 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
414 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
416 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
418 $logger->info("user update checking perm $perm on user ".
419 $requestor->id." for update/create on user username=".$patron->usrname);
421 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
429 my( $session, $patron, $user_obj, $noperm) = @_;
431 $logger->info("Updating patron ".$patron->id." in DB");
436 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
437 return (undef, $evt) if $evt;
440 # update the password by itself to avoid the password protection magic
441 if( $patron->passwd ) {
442 my $s = $session->request(
443 'open-ils.storage.direct.actor.user.remote_update',
444 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
445 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
446 $patron->clear_passwd;
449 if(!$patron->ident_type) {
450 $patron->clear_ident_type;
451 $patron->clear_ident_value;
454 $evt = verify_last_xact($session, $patron);
455 return (undef, $evt) if $evt;
457 my $stat = $session->request(
458 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
459 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
464 sub verify_last_xact {
465 my( $session, $patron ) = @_;
466 return undef unless $patron->id and $patron->id > 0;
467 my $p = $session->request(
468 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
469 my $xact = $p->last_xact_id;
470 return undef unless $xact;
471 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
472 return OpenILS::Event->new('XACT_COLLISION')
473 if $xact != $patron->last_xact_id;
478 sub _check_dup_ident {
479 my( $session, $patron ) = @_;
481 return undef unless $patron->ident_value;
484 ident_type => $patron->ident_type,
485 ident_value => $patron->ident_value,
488 $logger->debug("patron update searching for dup ident values: " .
489 $patron->ident_type . ':' . $patron->ident_value);
491 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
493 my $dups = $session->request(
494 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
497 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
504 sub _add_update_addresses {
508 my $new_patron = shift;
512 my $current_id; # id of the address before creation
514 for my $address (@{$patron->addresses()}) {
516 next unless ref $address;
517 $current_id = $address->id();
519 if( $patron->billing_address() and
520 $patron->billing_address() == $current_id ) {
521 $logger->info("setting billing addr to $current_id");
522 $new_patron->billing_address($address->id());
523 $new_patron->ischanged(1);
526 if( $patron->mailing_address() and
527 $patron->mailing_address() == $current_id ) {
528 $new_patron->mailing_address($address->id());
529 $logger->info("setting mailing addr to $current_id");
530 $new_patron->ischanged(1);
534 if($address->isnew()) {
536 $address->usr($new_patron->id());
538 ($address, $evt) = _add_address($session,$address);
539 return (undef, $evt) if $evt;
541 # we need to get the new id
542 if( $patron->billing_address() and
543 $patron->billing_address() == $current_id ) {
544 $new_patron->billing_address($address->id());
545 $logger->info("setting billing addr to $current_id");
546 $new_patron->ischanged(1);
549 if( $patron->mailing_address() and
550 $patron->mailing_address() == $current_id ) {
551 $new_patron->mailing_address($address->id());
552 $logger->info("setting mailing addr to $current_id");
553 $new_patron->ischanged(1);
556 } elsif($address->ischanged() ) {
558 ($address, $evt) = _update_address($session, $address);
559 return (undef, $evt) if $evt;
561 } elsif($address->isdeleted() ) {
563 if( $address->id() == $new_patron->mailing_address() ) {
564 $new_patron->clear_mailing_address();
565 ($new_patron, $evt) = _update_patron($session, $new_patron);
566 return (undef, $evt) if $evt;
569 if( $address->id() == $new_patron->billing_address() ) {
570 $new_patron->clear_billing_address();
571 ($new_patron, $evt) = _update_patron($session, $new_patron);
572 return (undef, $evt) if $evt;
575 $evt = _delete_address($session, $address);
576 return (undef, $evt) if $evt;
580 return ( $new_patron, undef );
584 # adds an address to the db and returns the address with new id
586 my($session, $address) = @_;
587 $address->clear_id();
589 $logger->info("Creating new address at street ".$address->street1);
591 # put the address into the database
592 my $id = $session->request(
593 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
594 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
597 return ($address, undef);
601 sub _update_address {
602 my( $session, $address ) = @_;
604 $logger->info("Updating address ".$address->id." in the DB");
606 my $stat = $session->request(
607 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
609 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
610 return ($address, undef);
615 sub _add_update_cards {
619 my $new_patron = shift;
623 my $virtual_id; #id of the card before creation
624 for my $card (@{$patron->cards()}) {
626 $card->usr($new_patron->id());
628 if(ref($card) and $card->isnew()) {
630 $virtual_id = $card->id();
631 ( $card, $evt ) = _add_card($session,$card);
632 return (undef, $evt) if $evt;
634 #if(ref($patron->card)) { $patron->card($patron->card->id); }
635 if($patron->card() == $virtual_id) {
636 $new_patron->card($card->id());
637 $new_patron->ischanged(1);
640 } elsif( ref($card) and $card->ischanged() ) {
641 $evt = _update_card($session, $card);
642 return (undef, $evt) if $evt;
646 return ( $new_patron, undef );
650 # adds an card to the db and returns the card with new id
652 my( $session, $card ) = @_;
655 $logger->info("Adding new patron card ".$card->barcode);
657 my $id = $session->request(
658 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
659 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
660 $logger->info("Successfully created patron card $id");
663 return ( $card, undef );
667 # returns event on error. returns undef otherwise
669 my( $session, $card ) = @_;
670 $logger->info("Updating patron card ".$card->id);
672 my $stat = $session->request(
673 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
674 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
681 # returns event on error. returns undef otherwise
682 sub _delete_address {
683 my( $session, $address ) = @_;
685 $logger->info("Deleting address ".$address->id." from DB");
687 my $stat = $session->request(
688 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
690 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
696 sub _add_survey_responses {
697 my ($session, $patron, $new_patron) = @_;
699 $logger->info( "Updating survey responses for patron ".$new_patron->id );
701 my $responses = $patron->survey_responses;
705 $_->usr($new_patron->id) for (@$responses);
707 my $evt = $U->simplereq( "open-ils.circ",
708 "open-ils.circ.survey.submit.user_id", $responses );
710 return (undef, $evt) if defined($U->event_code($evt));
714 return ( $new_patron, undef );
718 sub _create_stat_maps {
720 my($session, $user_session, $patron, $new_patron) = @_;
722 my $maps = $patron->stat_cat_entries();
724 for my $map (@$maps) {
726 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
728 if ($map->isdeleted()) {
729 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
731 } elsif ($map->isnew()) {
732 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
737 $map->target_usr($new_patron->id);
740 $logger->info("Updating stat entry with method $method and map $map");
742 my $stat = $session->request($method, $map)->gather(1);
743 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
747 return ($new_patron, undef);
750 sub _create_perm_maps {
752 my($session, $user_session, $patron, $new_patron) = @_;
754 my $maps = $patron->permissions;
756 for my $map (@$maps) {
758 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
759 if ($map->isdeleted()) {
760 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
761 } elsif ($map->isnew()) {
762 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
767 $map->usr($new_patron->id);
769 #warn( "Updating permissions with method $method and session $user_session and map $map" );
770 $logger->info( "Updating permissions with method $method and map $map" );
772 my $stat = $session->request($method, $map)->gather(1);
773 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
777 return ($new_patron, undef);
781 __PACKAGE__->register_method(
782 method => "set_user_perms",
783 api_name => "open-ils.actor.user.permissions.update",
792 my $session = $apputils->start_db_session();
794 my( $user_obj, $evt ) = $U->checkses($ses);
797 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
800 $all = 1 if ($user_obj->super_user());
801 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
803 for my $map (@$maps) {
805 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
806 if ($map->isdeleted()) {
807 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
808 } elsif ($map->isnew()) {
809 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
813 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
815 #warn( "Updating permissions with method $method and session $ses and map $map" );
816 $logger->info( "Updating permissions with method $method and map $map" );
818 my $stat = $session->request($method, $map)->gather(1);
819 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
823 $apputils->commit_db_session($session);
825 return scalar(@$maps);
829 sub _create_standing_penalties {
831 my($session, $user_session, $patron, $new_patron) = @_;
833 my $maps = $patron->standing_penalties;
836 for my $map (@$maps) {
838 if ($map->isdeleted()) {
839 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
840 } elsif ($map->isnew()) {
841 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
847 $map->usr($new_patron->id);
849 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
851 my $stat = $session->request($method, $map)->gather(1);
852 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
855 return ($new_patron, undef);
860 __PACKAGE__->register_method(
861 method => "search_username",
862 api_name => "open-ils.actor.user.search.username",
865 sub search_username {
866 my($self, $client, $username) = @_;
867 return new_editor()->search_actor_user({usrname=>$username});
873 __PACKAGE__->register_method(
874 method => "user_retrieve_by_barcode",
875 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
877 sub user_retrieve_by_barcode {
878 my($self, $client, $user_session, $barcode) = @_;
880 $logger->debug("Searching for user with barcode $barcode");
881 my ($user_obj, $evt) = $apputils->checkses($user_session);
884 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
886 "open-ils.cstore.direct.actor.card.search.atomic",
887 { barcode => $barcode }
890 if(!$card || !$card->[0]) {
891 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
895 my $user = flesh_user($card->usr());
897 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
900 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
907 __PACKAGE__->register_method(
908 method => "get_user_by_id",
909 api_name => "open-ils.actor.user.retrieve",);
912 my ($self, $client, $auth, $id) = @_;
913 my $e = new_editor(authtoken=>$auth);
914 return $e->event unless $e->checkauth;
915 my $user = $e->retrieve_actor_user($id)
917 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
923 __PACKAGE__->register_method(
924 method => "get_org_types",
925 api_name => "open-ils.actor.org_types.retrieve",);
929 my($self, $client) = @_;
930 return $org_types if $org_types;
931 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
936 __PACKAGE__->register_method(
937 method => "get_user_ident_types",
938 api_name => "open-ils.actor.user.ident_types.retrieve",
941 sub get_user_ident_types {
942 return $ident_types if $ident_types;
943 return $ident_types =
944 new_editor()->retrieve_all_config_identification_type();
950 __PACKAGE__->register_method(
951 method => "get_org_unit",
952 api_name => "open-ils.actor.org_unit.retrieve",
956 my( $self, $client, $user_session, $org_id ) = @_;
957 my $e = new_editor(authtoken => $user_session);
959 return $e->event unless $e->checkauth;
960 $org_id = $e->requestor->ws_ou;
962 my $o = $e->retrieve_actor_org_unit($org_id)
967 __PACKAGE__->register_method(
968 method => "search_org_unit",
969 api_name => "open-ils.actor.org_unit_list.search",
972 sub search_org_unit {
974 my( $self, $client, $field, $value ) = @_;
976 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
978 "open-ils.cstore.direct.actor.org_unit.search.atomic",
979 { $field => $value } );
987 __PACKAGE__->register_method(
988 method => "get_org_tree",
989 api_name => "open-ils.actor.org_tree.retrieve",
991 note => "Returns the entire org tree structure",
995 my( $self, $client) = @_;
997 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
998 my $tree = $cache->get_cache('orgtree');
999 return $tree if $tree;
1001 $tree = new_editor()->search_actor_org_unit(
1003 {"parent_ou" => undef },
1006 flesh_fields => { aou => ['children'] },
1007 order_by => { aou => 'name'}
1012 $cache->put_cache('orgtree', $tree);
1017 # turns an org list into an org tree
1018 sub build_org_tree {
1020 my( $self, $orglist) = @_;
1022 return $orglist unless ref $orglist;
1023 return $$orglist[0] if @$orglist == 1;
1026 $a->ou_type <=> $b->ou_type ||
1027 $a->name cmp $b->name } @$orglist;
1029 for my $org (@list) {
1031 next unless ($org and defined($org->parent_ou));
1032 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1033 next unless $parent;
1035 $parent->children([]) unless defined($parent->children);
1036 push( @{$parent->children}, $org );
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 ) = @_;
1052 my $orglist = $apputils->simple_scalar_request(
1054 "open-ils.storage.actor.org_unit.descendants.atomic",
1055 $org_unit, $depth );
1056 return $self->build_org_tree($orglist);
1060 __PACKAGE__->register_method(
1061 method => "get_org_ancestors",
1062 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1065 # depth is optional. org_unit is the id
1066 sub get_org_ancestors {
1067 my( $self, $client, $org_unit, $depth ) = @_;
1068 my $orglist = $apputils->simple_scalar_request(
1070 "open-ils.storage.actor.org_unit.ancestors.atomic",
1071 $org_unit, $depth );
1072 return $self->build_org_tree($orglist);
1076 __PACKAGE__->register_method(
1077 method => "get_standings",
1078 api_name => "open-ils.actor.standings.retrieve"
1083 return $user_standings if $user_standings;
1084 return $user_standings =
1085 $apputils->simple_scalar_request(
1087 "open-ils.cstore.direct.config.standing.search.atomic",
1088 { id => { "!=" => undef } }
1094 __PACKAGE__->register_method(
1095 method => "get_my_org_path",
1096 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1099 sub get_my_org_path {
1100 my( $self, $client, $auth, $org_id ) = @_;
1101 my $e = new_editor(authtoken=>$auth);
1102 return $e->event unless $e->checkauth;
1103 $org_id = $e->requestor->ws_ou unless defined $org_id;
1105 return $apputils->simple_scalar_request(
1107 "open-ils.storage.actor.org_unit.full_path.atomic",
1112 __PACKAGE__->register_method(
1113 method => "patron_adv_search",
1114 api_name => "open-ils.actor.patron.search.advanced" );
1115 sub patron_adv_search {
1116 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort, $include_inactive ) = @_;
1117 my $e = new_editor(authtoken=>$auth);
1118 return $e->event unless $e->checkauth;
1119 return $e->event unless $e->allowed('VIEW_USER');
1120 return $U->storagereq(
1121 "open-ils.storage.actor.user.crazy_search",
1122 $search_hash, $search_limit, $search_sort, $include_inactive);
1128 sub _verify_password {
1129 my($user_session, $password) = @_;
1130 my $user_obj = $apputils->check_user_session($user_session);
1132 #grab the user with password
1133 $user_obj = $apputils->simple_scalar_request(
1135 "open-ils.cstore.direct.actor.user.retrieve",
1138 if($user_obj->passwd eq $password) {
1146 __PACKAGE__->register_method(
1147 method => "update_password",
1148 api_name => "open-ils.actor.user.password.update");
1150 __PACKAGE__->register_method(
1151 method => "update_password",
1152 api_name => "open-ils.actor.user.username.update");
1154 __PACKAGE__->register_method(
1155 method => "update_password",
1156 api_name => "open-ils.actor.user.email.update");
1158 sub update_password {
1159 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1163 my $session = $apputils->start_db_session();
1164 my $user_obj = $apputils->check_user_session($user_session);
1166 #fetch the in-database version so we get the latest xact_id
1167 $user_obj = $session->request(
1168 'open-ils.storage.direct.actor.user.retrieve', $user_obj->id)->gather(1);
1170 if($self->api_name =~ /password/o) {
1172 #make sure they know the current password
1173 if(!_verify_password($user_session, md5_hex($current_password))) {
1174 return OpenILS::Event->new('INCORRECT_PASSWORD');
1177 $logger->debug("update_password setting new password $new_value");
1178 $user_obj->passwd($new_value);
1180 } elsif($self->api_name =~ /username/o) {
1181 my $users = search_username(undef, undef, $new_value);
1182 if( $users and $users->[0] ) {
1183 return OpenILS::Event->new('USERNAME_EXISTS');
1185 $user_obj->usrname($new_value);
1187 } elsif($self->api_name =~ /email/o) {
1188 #warn "Updating email to $new_value\n";
1189 $user_obj->email($new_value);
1193 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1194 return $evt if $evt;
1196 $apputils->commit_db_session($session);
1198 if($user_obj) { return 1; }
1203 __PACKAGE__->register_method(
1204 method => "update_passwd",
1205 api_name => "open-ils.actor.user.password.update");
1207 __PACKAGE__->register_method(
1208 method => "update_passwd",
1209 api_name => "open-ils.actor.user.username.update");
1211 __PACKAGE__->register_method(
1212 method => "update_passwd",
1213 api_name => "open-ils.actor.user.email.update");
1216 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1217 my $e = new_editor(xact=>1, authtoken=>$auth);
1218 return $e->die_event unless $e->checkauth;
1220 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1221 or return $e->die_event;
1222 my $api = $self->api_name;
1224 if( $api =~ /password/o ) {
1226 # make sure the original password matches the in-database password
1227 return OpenILS::Event->new('INCORRECT_PASSWORD')
1228 if md5_hex($orig_pw) ne $db_user->passwd;
1229 $db_user->passwd($new_val);
1233 # if we don't clear the password, the user will be updated with
1234 # a hashed version of the hashed version of their password
1235 $db_user->clear_passwd;
1237 if( $api =~ /username/o ) {
1239 # make sure no one else has this username
1240 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1241 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1242 $db_user->usrname($new_val);
1244 } elsif( $api =~ /email/o ) {
1245 $db_user->email($new_val);
1249 $e->update_actor_user($db_user) or return $e->die_event;
1257 __PACKAGE__->register_method(
1258 method => "check_user_perms",
1259 api_name => "open-ils.actor.user.perm.check",
1260 notes => <<" NOTES");
1261 Takes a login session, user id, an org id, and an array of perm type strings. For each
1262 perm type, if the user does *not* have the given permission it is added
1263 to a list which is returned from the method. If all permissions
1264 are allowed, an empty list is returned
1265 if the logged in user does not match 'user_id', then the logged in user must
1266 have VIEW_PERMISSION priveleges.
1269 sub check_user_perms {
1270 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1272 my( $staff, $evt ) = $apputils->checkses($login_session);
1273 return $evt if $evt;
1275 if($staff->id ne $user_id) {
1276 if( $evt = $apputils->check_perms(
1277 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1283 for my $perm (@$perm_types) {
1284 if($apputils->check_perms($user_id, $org_id, $perm)) {
1285 push @not_allowed, $perm;
1289 return \@not_allowed
1292 __PACKAGE__->register_method(
1293 method => "check_user_perms2",
1294 api_name => "open-ils.actor.user.perm.check.multi_org",
1296 Checks the permissions on a list of perms and orgs for a user
1297 @param authtoken The login session key
1298 @param user_id The id of the user to check
1299 @param orgs The array of org ids
1300 @param perms The array of permission names
1301 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1302 if the logged in user does not match 'user_id', then the logged in user must
1303 have VIEW_PERMISSION priveleges.
1306 sub check_user_perms2 {
1307 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1309 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1310 $authtoken, $user_id, 'VIEW_PERMISSION' );
1311 return $evt if $evt;
1314 for my $org (@$orgs) {
1315 for my $perm (@$perms) {
1316 if($apputils->check_perms($user_id, $org, $perm)) {
1317 push @not_allowed, [ $org, $perm ];
1322 return \@not_allowed
1326 __PACKAGE__->register_method(
1327 method => 'check_user_perms3',
1328 api_name => 'open-ils.actor.user.perm.highest_org',
1330 Returns the highest org unit id at which a user has a given permission
1331 If the requestor does not match the target user, the requestor must have
1332 'VIEW_PERMISSION' rights at the home org unit of the target user
1333 @param authtoken The login session key
1334 @param userid The id of the user in question
1335 @param perm The permission to check
1336 @return The org unit highest in the org tree within which the user has
1337 the requested permission
1340 sub check_user_perms3 {
1341 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1343 my( $staff, $target, $org, $evt );
1345 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1346 $authtoken, $userid, 'VIEW_PERMISSION' );
1347 return $evt if $evt;
1349 my $tree = $self->get_org_tree();
1350 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1354 sub _find_highest_perm_org {
1355 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1356 my $org = $apputils->find_org($org_tree, $start_org );
1360 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1362 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1368 __PACKAGE__->register_method(
1369 method => 'check_user_perms4',
1370 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1372 Returns the highest org unit id at which a user has a given permission
1373 If the requestor does not match the target user, the requestor must have
1374 'VIEW_PERMISSION' rights at the home org unit of the target user
1375 @param authtoken The login session key
1376 @param userid The id of the user in question
1377 @param perms An array of perm names to check
1378 @return An array of orgId's representing the org unit
1379 highest in the org tree within which the user has the requested permission
1380 The arrah of orgId's has matches the order of the perms array
1383 sub check_user_perms4 {
1384 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1386 my( $staff, $target, $org, $evt );
1388 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1389 $authtoken, $userid, 'VIEW_PERMISSION' );
1390 return $evt if $evt;
1393 return [] unless ref($perms);
1394 my $tree = $self->get_org_tree();
1396 for my $p (@$perms) {
1397 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1405 __PACKAGE__->register_method(
1406 method => "user_fines_summary",
1407 api_name => "open-ils.actor.user.fines.summary",
1408 notes => <<" NOTES");
1409 Returns a short summary of the users total open fines, excluding voided fines
1410 Params are login_session, user_id
1411 Returns a 'mous' object.
1414 sub user_fines_summary {
1415 my( $self, $client, $auth, $user_id ) = @_;
1416 my $e = new_editor(authtoken=>$auth);
1417 return $e->event unless $e->checkauth;
1418 my $user = $e->retrieve_actor_user($user_id)
1419 or return $e->event;
1421 if( $user_id ne $e->requestor->id ) {
1422 return $e->event unless
1423 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1426 # run this inside a transaction to prevent replication delay errors
1427 my $ses = $U->start_db_session();
1428 my $s = $ses->request(
1429 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1430 $U->rollback_db_session($ses);
1437 __PACKAGE__->register_method(
1438 method => "user_transactions",
1439 api_name => "open-ils.actor.user.transactions",
1440 notes => <<" NOTES");
1441 Returns a list of open user transactions (mbts objects);
1442 Params are login_session, user_id
1443 Optional third parameter is the transactions type. defaults to all
1446 __PACKAGE__->register_method(
1447 method => "user_transactions",
1448 api_name => "open-ils.actor.user.transactions.have_charge",
1449 notes => <<" NOTES");
1450 Returns a list of all open user transactions (mbts objects) that have an initial charge
1451 Params are login_session, user_id
1452 Optional third parameter is the transactions type. defaults to all
1455 __PACKAGE__->register_method(
1456 method => "user_transactions",
1457 api_name => "open-ils.actor.user.transactions.have_balance",
1458 notes => <<" NOTES");
1459 Returns a list of all open user transactions (mbts objects) that have a balance
1460 Params are login_session, user_id
1461 Optional third parameter is the transactions type. defaults to all
1464 __PACKAGE__->register_method(
1465 method => "user_transactions",
1466 api_name => "open-ils.actor.user.transactions.fleshed",
1467 notes => <<" NOTES");
1468 Returns an object/hash of transaction, circ, title where transaction = an open
1469 user transactions (mbts objects), circ is the attached circluation, and title
1470 is the title the circ points to
1471 Params are login_session, user_id
1472 Optional third parameter is the transactions type. defaults to all
1475 __PACKAGE__->register_method(
1476 method => "user_transactions",
1477 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1478 notes => <<" NOTES");
1479 Returns an object/hash of transaction, circ, title where transaction = an open
1480 user transactions that has an initial charge (mbts objects), circ is the
1481 attached circluation, and title is the title the circ points to
1482 Params are login_session, user_id
1483 Optional third parameter is the transactions type. defaults to all
1486 __PACKAGE__->register_method(
1487 method => "user_transactions",
1488 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1489 notes => <<" NOTES");
1490 Returns an object/hash of transaction, circ, title where transaction = an open
1491 user transaction that has a balance (mbts objects), circ is the attached
1492 circluation, and title is the title the circ points to
1493 Params are login_session, user_id
1494 Optional third parameter is the transaction type. defaults to all
1497 __PACKAGE__->register_method(
1498 method => "user_transactions",
1499 api_name => "open-ils.actor.user.transactions.count",
1500 notes => <<" NOTES");
1501 Returns an object/hash of transaction, circ, title where transaction = an open
1502 user transactions (mbts objects), circ is the attached circluation, and title
1503 is the title the circ points to
1504 Params are login_session, user_id
1505 Optional third parameter is the transactions type. defaults to all
1508 __PACKAGE__->register_method(
1509 method => "user_transactions",
1510 api_name => "open-ils.actor.user.transactions.have_charge.count",
1511 notes => <<" NOTES");
1512 Returns an object/hash of transaction, circ, title where transaction = an open
1513 user transactions that has an initial charge (mbts objects), circ is the
1514 attached circluation, and title is the title the circ points to
1515 Params are login_session, user_id
1516 Optional third parameter is the transactions type. defaults to all
1519 __PACKAGE__->register_method(
1520 method => "user_transactions",
1521 api_name => "open-ils.actor.user.transactions.have_balance.count",
1522 notes => <<" NOTES");
1523 Returns an object/hash of transaction, circ, title where transaction = an open
1524 user transaction that has a balance (mbts objects), circ is the attached
1525 circluation, and title is the title the circ points to
1526 Params are login_session, user_id
1527 Optional third parameter is the transaction type. defaults to all
1530 __PACKAGE__->register_method(
1531 method => "user_transactions",
1532 api_name => "open-ils.actor.user.transactions.have_balance.total",
1533 notes => <<" NOTES");
1534 Returns an object/hash of transaction, circ, title where transaction = an open
1535 user transaction that has a balance (mbts objects), circ is the attached
1536 circluation, and title is the title the circ points to
1537 Params are login_session, user_id
1538 Optional third parameter is the transaction type. defaults to all
1543 sub user_transactions {
1544 my( $self, $client, $login_session, $user_id, $type ) = @_;
1546 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1547 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1548 return $evt if $evt;
1550 my $api = $self->api_name();
1554 if(defined($type)) { @xact = (xact_type => $type);
1556 } else { @xact = (); }
1559 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1560 ->run($login_session => $user_id => $type);
1562 if($api =~ /have_charge/o) {
1564 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1566 } elsif($api =~ /have_balance/o) {
1568 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1571 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1575 if($api =~ /total/o) {
1577 for my $t (@$trans) {
1578 $total += $t->balance_owed;
1581 $logger->debug("Total balance owed by user $user_id: $total");
1585 if($api =~ /count/o) { return scalar @$trans; }
1586 if($api !~ /fleshed/o) { return $trans; }
1589 for my $t (@$trans) {
1591 if( $t->xact_type ne 'circulation' ) {
1592 push @resp, {transaction => $t};
1596 my $circ = $apputils->simple_scalar_request(
1598 "open-ils.cstore.direct.action.circulation.retrieve",
1603 my $title = $apputils->simple_scalar_request(
1605 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1606 $circ->target_copy );
1610 my $u = OpenILS::Utils::ModsParser->new();
1611 $u->start_mods_batch($title->marc());
1612 my $mods = $u->finish_mods_batch();
1613 $mods->doc_id($title->id) if $mods;
1615 push @resp, {transaction => $t, circ => $circ, record => $mods };
1623 __PACKAGE__->register_method(
1624 method => "user_transaction_retrieve",
1625 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1627 notes => <<" NOTES");
1628 Returns a fleshedtransaction record
1630 __PACKAGE__->register_method(
1631 method => "user_transaction_retrieve",
1632 api_name => "open-ils.actor.user.transaction.retrieve",
1634 notes => <<" NOTES");
1635 Returns a transaction record
1637 sub user_transaction_retrieve {
1638 my( $self, $client, $login_session, $bill_id ) = @_;
1640 # XXX I think I'm deprecated... make sure
1642 my $trans = $apputils->simple_scalar_request(
1644 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1648 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1649 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1650 return $evt if $evt;
1652 my $api = $self->api_name();
1653 if($api !~ /fleshed/o) { return $trans; }
1655 if( $trans->xact_type ne 'circulation' ) {
1656 $logger->debug("Returning non-circ transaction");
1657 return {transaction => $trans};
1660 my $circ = $apputils->simple_scalar_request(
1662 "open-ils..direct.action.circulation.retrieve",
1665 return {transaction => $trans} unless $circ;
1666 $logger->debug("Found the circ transaction");
1668 my $title = $apputils->simple_scalar_request(
1670 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1671 $circ->target_copy );
1673 return {transaction => $trans, circ => $circ } unless $title;
1674 $logger->debug("Found the circ title");
1678 my $u = OpenILS::Utils::ModsParser->new();
1679 $u->start_mods_batch($title->marc());
1680 $mods = $u->finish_mods_batch();
1682 if ($title->id == OILS_PRECAT_RECORD) {
1683 my $copy = $apputils->simple_scalar_request(
1685 "open-ils.cstore.direct.asset.copy.retrieve",
1686 $circ->target_copy );
1688 $mods = new Fieldmapper::metabib::virtual_record;
1689 $mods->doc_id(OILS_PRECAT_RECORD);
1690 $mods->title($copy->dummy_title);
1691 $mods->author($copy->dummy_author);
1695 $logger->debug("MODSized the circ title");
1697 return {transaction => $trans, circ => $circ, record => $mods };
1701 __PACKAGE__->register_method(
1702 method => "hold_request_count",
1703 api_name => "open-ils.actor.user.hold_requests.count",
1705 notes => <<" NOTES");
1706 Returns hold ready/total counts
1708 sub hold_request_count {
1709 my( $self, $client, $login_session, $userid ) = @_;
1711 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1712 $login_session, $userid, 'VIEW_HOLD' );
1713 return $evt if $evt;
1716 my $holds = $apputils->simple_scalar_request(
1718 "open-ils.cstore.direct.action.hold_request.search.atomic",
1721 fulfillment_time => {"=" => undef },
1722 cancel_time => undef,
1727 for my $h (@$holds) {
1728 next unless $h->capture_time and $h->current_copy;
1730 my $copy = $apputils->simple_scalar_request(
1732 "open-ils.cstore.direct.asset.copy.retrieve",
1736 if ($copy and $copy->status == 8) {
1741 return { total => scalar(@$holds), ready => scalar(@ready) };
1745 __PACKAGE__->register_method(
1746 method => "checkedout_count",
1747 api_name => "open-ils.actor.user.checked_out.count__",
1749 notes => <<" NOTES");
1750 Returns a transaction record
1754 sub checkedout_count {
1755 my( $self, $client, $login_session, $userid ) = @_;
1757 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1758 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1759 return $evt if $evt;
1761 my $circs = $apputils->simple_scalar_request(
1763 "open-ils.cstore.direct.action.circulation.search.atomic",
1764 { usr => $userid, stop_fines => undef }
1765 #{ usr => $userid, checkin_time => {"=" => undef } }
1768 my $parser = DateTime::Format::ISO8601->new;
1771 for my $c (@$circs) {
1772 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1773 my $due = $due_dt->epoch;
1775 if ($due < DateTime->today->epoch) {
1780 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1784 __PACKAGE__->register_method(
1785 method => "checked_out",
1786 api_name => "open-ils.actor.user.checked_out",
1789 Returns a structure of circulations objects sorted by
1790 out, overdue, lost, claims_returned, long_overdue.
1791 A list of IDs are returned of each type.
1792 lost, long_overdue, and claims_returned circ will not
1793 be "finished" (there is an outstanding balance or some
1794 other pending action on the circ).
1796 The .count method also includes a 'total' field which
1797 sums all "open" circs
1801 __PACKAGE__->register_method(
1802 method => "checked_out",
1803 api_name => "open-ils.actor.user.checked_out.count",
1805 signature => q/@see open-ils.actor.user.checked_out/
1809 my( $self, $conn, $auth, $userid ) = @_;
1811 my $e = new_editor(authtoken=>$auth);
1812 return $e->event unless $e->checkauth;
1814 if( $userid ne $e->requestor->id ) {
1815 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1818 my $count = $self->api_name =~ /count/;
1819 return _checked_out( $count, $e, $userid );
1823 my( $iscount, $e, $userid ) = @_;
1826 my $meth = 'open-ils.storage.actor.user.checked_out';
1827 $meth = "$meth.count" if $iscount;
1828 return $U->storagereq($meth, $userid);
1830 # XXX Old code - moved to storage
1831 #------------------------------------------------------------------------------
1832 #------------------------------------------------------------------------------
1833 my $circs = $e->search_action_circulation(
1834 { usr => $userid, checkin_time => undef });
1836 my $parser = DateTime::Format::ISO8601->new;
1838 # split the circs up into overdue and not-overdue circs
1840 for my $c (@$circs) {
1841 if( $c->due_date ) {
1842 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1843 my $due = $due_dt->epoch;
1844 if ($due < DateTime->today->epoch) {
1854 my( @open, @od, @lost, @cr, @lo );
1856 while (my $c = shift(@out)) {
1857 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1858 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1859 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1860 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1863 while (my $c = shift(@overdue)) {
1864 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1865 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1866 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1867 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1872 total => @open + @od + @lost + @cr + @lo,
1873 out => scalar(@open),
1874 overdue => scalar(@od),
1875 lost => scalar(@lost),
1876 claims_returned => scalar(@cr),
1877 long_overdue => scalar(@lo)
1885 claims_returned => \@cr,
1886 long_overdue => \@lo
1891 sub _checked_out_WHAT {
1892 my( $iscount, $e, $userid ) = @_;
1894 my $circs = $e->search_action_circulation(
1895 { usr => $userid, stop_fines => undef });
1897 my $mcircs = $e->search_action_circulation(
1900 checkin_time => undef,
1901 xact_finish => undef,
1905 push( @$circs, @$mcircs );
1907 my $parser = DateTime::Format::ISO8601->new;
1909 # split the circs up into overdue and not-overdue circs
1911 for my $c (@$circs) {
1912 if( $c->due_date ) {
1913 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1914 my $due = $due_dt->epoch;
1915 if ($due < DateTime->today->epoch) {
1916 push @overdue, $c->id;
1925 # grab all of the lost, claims-returned, and longoverdue circs
1926 #my $open = $e->search_action_circulation(
1927 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1930 # these items have stop_fines, but no xact_finish, so money
1931 # is owed on them and they have not been checked in
1932 my $open = $e->search_action_circulation(
1935 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1936 xact_finish => undef,
1937 checkin_time => undef,
1942 my( @lost, @cr, @lo );
1943 for my $c (@$open) {
1944 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1945 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1946 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1952 total => @$circs + @lost + @cr + @lo,
1953 out => scalar(@out),
1954 overdue => scalar(@overdue),
1955 lost => scalar(@lost),
1956 claims_returned => scalar(@cr),
1957 long_overdue => scalar(@lo)
1963 overdue => \@overdue,
1965 claims_returned => \@cr,
1966 long_overdue => \@lo
1972 __PACKAGE__->register_method(
1973 method => "checked_in_with_fines",
1974 api_name => "open-ils.actor.user.checked_in_with_fines",
1976 signature => q/@see open-ils.actor.user.checked_out/
1978 sub checked_in_with_fines {
1979 my( $self, $conn, $auth, $userid ) = @_;
1981 my $e = new_editor(authtoken=>$auth);
1982 return $e->event unless $e->checkauth;
1984 if( $userid ne $e->requestor->id ) {
1985 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1988 # money is owed on these items and they are checked in
1989 my $open = $e->search_action_circulation(
1992 xact_finish => undef,
1993 checkin_time => { "!=" => undef },
1998 my( @lost, @cr, @lo );
1999 for my $c (@$open) {
2000 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2001 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2002 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2007 claims_returned => \@cr,
2008 long_overdue => \@lo
2020 __PACKAGE__->register_method(
2021 method => "user_transaction_history",
2022 api_name => "open-ils.actor.user.transactions.history",
2024 notes => <<" NOTES");
2025 Returns a list of billable transaction ids for a user, optionally by type
2027 __PACKAGE__->register_method(
2028 method => "user_transaction_history",
2029 api_name => "open-ils.actor.user.transactions.history.have_charge",
2031 notes => <<" NOTES");
2032 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2034 __PACKAGE__->register_method(
2035 method => "user_transaction_history",
2036 api_name => "open-ils.actor.user.transactions.history.have_balance",
2038 notes => <<" NOTES");
2039 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2041 __PACKAGE__->register_method(
2042 method => "user_transaction_history",
2043 api_name => "open-ils.actor.user.transactions.history.still_open",
2045 notes => <<" NOTES");
2046 Returns a list of billable transaction ids for a user that are not finished
2048 __PACKAGE__->register_method(
2049 method => "user_transaction_history",
2050 api_name => "open-ils.actor.user.transactions.history.have_bill",
2052 notes => <<" NOTES");
2053 Returns a list of billable transaction ids for a user that has billings
2059 sub _user_transaction_history {
2060 my( $self, $client, $login_session, $user_id, $type ) = @_;
2062 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2063 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2064 return $evt if $evt;
2066 my $api = $self->api_name();
2071 @xact = (xact_type => $type) if(defined($type));
2072 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2073 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2075 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2077 my $trans = $apputils->simple_scalar_request(
2079 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2080 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2082 return [ map { $_->id } @$trans ];
2086 =head SEE APPUTILS.PM
2091 for my $x (@xacts) {
2092 my $s = new Fieldmapper::money::billable_transaction_summary;
2095 $s->xact_start( $x->xact_start );
2096 $s->xact_finish( $x->xact_finish );
2100 for my $b (@{ $x->billings }) {
2101 next if ($U->is_true($b->voided));
2102 $to += ($b->amount * 100);
2103 $lb ||= $b->billing_ts;
2104 if ($b->billing_ts ge $lb) {
2105 $lb = $b->billing_ts;
2106 $s->last_billing_note($b->note);
2107 $s->last_billing_ts($b->billing_ts);
2108 $s->last_billing_type($b->billing_type);
2112 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2116 for my $p (@{ $x->payments }) {
2117 next if ($U->is_true($p->voided));
2118 $tp += ($p->amount * 100);
2119 $lp ||= $p->payment_ts;
2120 if ($p->payment_ts ge $lp) {
2121 $lp = $p->payment_ts;
2122 $s->last_payment_note($p->note);
2123 $s->last_payment_ts($p->payment_ts);
2124 $s->last_payment_type($p->payment_type);
2127 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2129 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2131 $s->xact_type( 'grocery' ) if ($x->grocery);
2132 $s->xact_type( 'circulation' ) if ($x->circulation);
2141 sub user_transaction_history {
2142 my( $self, $conn, $auth, $userid, $type ) = @_;
2144 # run inside of a transaction to prevent replication delays
2145 my $e = new_editor(xact=>1, authtoken=>$auth);
2146 return $e->die_event unless $e->checkauth;
2148 if( $e->requestor->id ne $userid ) {
2149 return $e->die_event
2150 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2153 my $api = $self->api_name;
2154 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2156 my @xacts = @{ $e->search_money_billable_transaction(
2157 [ { usr => $userid, @xact_finish },
2159 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2160 order_by => { mbt => 'xact_start DESC' },
2168 #my @mbts = _make_mbts( @xacts );
2169 my @mbts = $U->make_mbts( @xacts );
2171 if(defined($type)) {
2172 @mbts = grep { $_->xact_type eq $type } @mbts;
2175 if($api =~ /have_balance/o) {
2176 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2179 if($api =~ /have_charge/o) {
2180 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2183 if($api =~ /have_bill/o) {
2184 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2192 __PACKAGE__->register_method(
2193 method => "user_perms",
2194 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2196 notes => <<" NOTES");
2197 Returns a list of permissions
2200 my( $self, $client, $authtoken, $user ) = @_;
2202 my( $staff, $evt ) = $apputils->checkses($authtoken);
2203 return $evt if $evt;
2205 $user ||= $staff->id;
2207 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2211 return $apputils->simple_scalar_request(
2213 "open-ils.storage.permission.user_perms.atomic",
2217 __PACKAGE__->register_method(
2218 method => "retrieve_perms",
2219 api_name => "open-ils.actor.permissions.retrieve",
2220 notes => <<" NOTES");
2221 Returns a list of permissions
2223 sub retrieve_perms {
2224 my( $self, $client ) = @_;
2225 return $apputils->simple_scalar_request(
2227 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2228 { id => { '!=' => undef } }
2232 __PACKAGE__->register_method(
2233 method => "retrieve_groups",
2234 api_name => "open-ils.actor.groups.retrieve",
2235 notes => <<" NOTES");
2236 Returns a list of user groupss
2238 sub retrieve_groups {
2239 my( $self, $client ) = @_;
2240 return new_editor()->retrieve_all_permission_grp_tree();
2243 __PACKAGE__->register_method(
2244 method => "retrieve_org_address",
2245 api_name => "open-ils.actor.org_unit.address.retrieve",
2246 notes => <<' NOTES');
2247 Returns an org_unit address by ID
2248 @param An org_address ID
2250 sub retrieve_org_address {
2251 my( $self, $client, $id ) = @_;
2252 return $apputils->simple_scalar_request(
2254 "open-ils.cstore.direct.actor.org_address.retrieve",
2259 __PACKAGE__->register_method(
2260 method => "retrieve_groups_tree",
2261 api_name => "open-ils.actor.groups.tree.retrieve",
2262 notes => <<" NOTES");
2263 Returns a list of user groups
2265 sub retrieve_groups_tree {
2266 my( $self, $client ) = @_;
2267 return new_editor()->search_permission_grp_tree(
2272 flesh_fields => { pgt => ["children"] },
2273 order_by => { pgt => 'name'}
2280 # turns an org list into an org tree
2282 sub build_group_tree {
2284 my( $self, $grplist) = @_;
2286 return $grplist unless (
2287 ref($grplist) and @$grplist > 1 );
2289 my @list = sort { $a->name cmp $b->name } @$grplist;
2292 for my $grp (@list) {
2294 if ($grp and !defined($grp->parent)) {
2298 my ($parent) = grep { $_->id == $grp->parent} @list;
2300 $parent->children([]) unless defined($parent->children);
2301 push( @{$parent->children}, $grp );
2309 __PACKAGE__->register_method(
2310 method => "add_user_to_groups",
2311 api_name => "open-ils.actor.user.set_groups",
2312 notes => <<" NOTES");
2313 Adds a user to one or more permission groups
2316 sub add_user_to_groups {
2317 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2319 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2320 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2321 return $evt if $evt;
2323 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2324 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2325 return $evt if $evt;
2327 $apputils->simplereq(
2329 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2331 for my $group (@$groups) {
2332 my $link = Fieldmapper::permission::usr_grp_map->new;
2334 $link->usr($userid);
2336 my $id = $apputils->simplereq(
2338 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2344 __PACKAGE__->register_method(
2345 method => "get_user_perm_groups",
2346 api_name => "open-ils.actor.user.get_groups",
2347 notes => <<" NOTES");
2348 Retrieve a user's permission groups.
2352 sub get_user_perm_groups {
2353 my( $self, $client, $authtoken, $userid ) = @_;
2355 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2356 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2357 return $evt if $evt;
2359 return $apputils->simplereq(
2361 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2366 __PACKAGE__->register_method (
2367 method => 'register_workstation',
2368 api_name => 'open-ils.actor.workstation.register.override',
2369 signature => q/@see open-ils.actor.workstation.register/);
2371 __PACKAGE__->register_method (
2372 method => 'register_workstation',
2373 api_name => 'open-ils.actor.workstation.register',
2375 Registers a new workstion in the system
2376 @param authtoken The login session key
2377 @param name The name of the workstation id
2378 @param owner The org unit that owns this workstation
2379 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2380 if the name is already in use.
2383 sub _register_workstation {
2384 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2385 my( $requestor, $evt ) = $U->checkses($authtoken);
2386 return $evt if $evt;
2387 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2388 return $evt if $evt;
2390 my $ws = $U->cstorereq(
2391 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2392 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2394 $ws = Fieldmapper::actor::workstation->new;
2395 $ws->owning_lib($owner);
2398 my $id = $U->storagereq(
2399 'open-ils.storage.direct.actor.workstation.create', $ws );
2400 return $U->DB_UPDATE_FAILED($ws) unless $id;
2406 sub register_workstation {
2407 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2409 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2410 return $e->event unless $e->checkauth;
2411 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2412 my $existing = $e->search_actor_workstation({name => $name});
2415 if( $self->api_name =~ /override/o ) {
2416 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2417 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2419 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2423 my $ws = Fieldmapper::actor::workstation->new;
2424 $ws->owning_lib($owner);
2426 $e->create_actor_workstation($ws) or return $e->event;
2428 return $ws->id; # note: editor sets the id on the new object for us
2432 __PACKAGE__->register_method (
2433 method => 'fetch_patron_note',
2434 api_name => 'open-ils.actor.note.retrieve.all',
2436 Returns a list of notes for a given user
2437 Requestor must have VIEW_USER permission if pub==false and
2438 @param authtoken The login session key
2439 @param args Hash of params including
2440 patronid : the patron's id
2441 pub : true if retrieving only public notes
2445 sub fetch_patron_note {
2446 my( $self, $conn, $authtoken, $args ) = @_;
2447 my $patronid = $$args{patronid};
2449 my($reqr, $evt) = $U->checkses($authtoken);
2450 return $evt if $evt;
2453 ($patron, $evt) = $U->fetch_user($patronid);
2454 return $evt if $evt;
2457 if( $patronid ne $reqr->id ) {
2458 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2459 return $evt if $evt;
2461 return $U->cstorereq(
2462 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2463 { usr => $patronid, pub => 't' } );
2466 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2467 return $evt if $evt;
2469 return $U->cstorereq(
2470 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2473 __PACKAGE__->register_method (
2474 method => 'create_user_note',
2475 api_name => 'open-ils.actor.note.create',
2477 Creates a new note for the given user
2478 @param authtoken The login session key
2479 @param note The note object
2482 sub create_user_note {
2483 my( $self, $conn, $authtoken, $note ) = @_;
2484 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2485 return $e->die_event unless $e->checkauth;
2487 my $user = $e->retrieve_actor_user($note->usr)
2488 or return $e->die_event;
2490 return $e->die_event unless
2491 $e->allowed('UPDATE_USER',$user->home_ou);
2493 $note->creator($e->requestor->id);
2494 $e->create_actor_usr_note($note) or return $e->die_event;
2500 __PACKAGE__->register_method (
2501 method => 'delete_user_note',
2502 api_name => 'open-ils.actor.note.delete',
2504 Deletes a note for the given user
2505 @param authtoken The login session key
2506 @param noteid The note id
2509 sub delete_user_note {
2510 my( $self, $conn, $authtoken, $noteid ) = @_;
2512 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2513 return $e->die_event unless $e->checkauth;
2514 my $note = $e->retrieve_actor_usr_note($noteid)
2515 or return $e->die_event;
2516 my $user = $e->retrieve_actor_user($note->usr)
2517 or return $e->die_event;
2518 return $e->die_event unless
2519 $e->allowed('UPDATE_USER', $user->home_ou);
2521 $e->delete_actor_usr_note($note) or return $e->die_event;
2527 __PACKAGE__->register_method (
2528 method => 'update_user_note',
2529 api_name => 'open-ils.actor.note.update',
2531 @param authtoken The login session key
2532 @param note The note
2536 sub update_user_note {
2537 my( $self, $conn, $auth, $note ) = @_;
2538 my $e = new_editor(authtoken=>$auth, xact=>1);
2539 return $e->event unless $e->checkauth;
2540 my $patron = $e->retrieve_actor_user($note->usr)
2541 or return $e->event;
2542 return $e->event unless
2543 $e->allowed('UPDATE_USER', $patron->home_ou);
2544 $e->update_actor_user_note($note)
2545 or return $e->event;
2553 __PACKAGE__->register_method (
2554 method => 'create_closed_date',
2555 api_name => 'open-ils.actor.org_unit.closed_date.create',
2557 Creates a new closing entry for the given org_unit
2558 @param authtoken The login session key
2559 @param note The closed_date object
2562 sub create_closed_date {
2563 my( $self, $conn, $authtoken, $cd ) = @_;
2565 my( $user, $evt ) = $U->checkses($authtoken);
2566 return $evt if $evt;
2568 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2569 return $evt if $evt;
2571 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2573 my $id = $U->storagereq(
2574 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2575 return $U->DB_UPDATE_FAILED($cd) unless $id;
2580 __PACKAGE__->register_method (
2581 method => 'delete_closed_date',
2582 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2584 Deletes a closing entry for the given org_unit
2585 @param authtoken The login session key
2586 @param noteid The close_date id
2589 sub delete_closed_date {
2590 my( $self, $conn, $authtoken, $cd ) = @_;
2592 my( $user, $evt ) = $U->checkses($authtoken);
2593 return $evt if $evt;
2596 ($cd_obj, $evt) = fetch_closed_date($cd);
2597 return $evt if $evt;
2599 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2600 return $evt if $evt;
2602 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2604 my $stat = $U->storagereq(
2605 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2606 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2611 __PACKAGE__->register_method(
2612 method => 'usrname_exists',
2613 api_name => 'open-ils.actor.username.exists',
2615 Returns 1 if the requested username exists, returns 0 otherwise
2619 sub usrname_exists {
2620 my( $self, $conn, $auth, $usrname ) = @_;
2621 my $e = new_editor(authtoken=>$auth);
2622 return $e->event unless $e->checkauth;
2623 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2624 return $$a[0] if $a and @$a;
2628 __PACKAGE__->register_method(
2629 method => 'barcode_exists',
2630 api_name => 'open-ils.actor.barcode.exists',
2632 Returns 1 if the requested barcode exists, returns 0 otherwise
2636 sub barcode_exists {
2637 my( $self, $conn, $auth, $barcode ) = @_;
2638 my $e = new_editor(authtoken=>$auth);
2639 return $e->event unless $e->checkauth;
2640 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2641 return $$a[0] if $a and @$a;
2646 __PACKAGE__->register_method(
2647 method => 'retrieve_net_levels',
2648 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2651 sub retrieve_net_levels {
2652 my( $self, $conn, $auth ) = @_;
2653 my $e = new_editor(authtoken=>$auth);
2654 return $e->event unless $e->checkauth;
2655 return $e->retrieve_all_config_net_access_level();
2659 __PACKAGE__->register_method(
2660 method => 'fetch_org_by_shortname',
2661 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2663 sub fetch_org_by_shortname {
2664 my( $self, $conn, $sname ) = @_;
2665 my $e = new_editor();
2666 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2667 return $e->event unless $org;
2672 __PACKAGE__->register_method(
2673 method => 'session_home_lib',
2674 api_name => 'open-ils.actor.session.home_lib',
2677 sub session_home_lib {
2678 my( $self, $conn, $auth ) = @_;
2679 my $e = new_editor(authtoken=>$auth);
2680 return undef unless $e->checkauth;
2681 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2682 return $org->shortname;
2685 __PACKAGE__->register_method(
2686 method => 'session_safe_token',
2687 api_name => 'open-ils.actor.session.safe_token',
2689 Returns a hashed session ID that is safe for export to the world.
2690 This safe token will expire after 1 hour of non-use.
2691 @param auth Active authentication token
2695 sub session_safe_token {
2696 my( $self, $conn, $auth ) = @_;
2697 my $e = new_editor(authtoken=>$auth);
2698 return undef unless $e->checkauth;
2700 my $safe_token = md5_hex($auth);
2702 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2704 # Add more like the following if needed...
2706 "safe-token-home_lib-shortname-$safe_token",
2707 $e->retrieve_actor_org_unit(
2708 $e->requestor->home_ou
2717 __PACKAGE__->register_method(
2718 method => 'safe_token_home_lib',
2719 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2721 Returns the home library shortname from the session
2722 asscociated with a safe token from generated by
2723 open-ils.actor.session.safe_token.
2724 @param safe_token Active safe token
2728 sub safe_token_home_lib {
2729 my( $self, $conn, $safe_token ) = @_;
2731 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2732 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2737 __PACKAGE__->register_method(
2738 method => 'slim_tree',
2739 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2742 my $tree = new_editor()->search_actor_org_unit(
2744 {"parent_ou" => undef },
2747 flesh_fields => { aou => ['children'] },
2748 order_by => { aou => 'name'},
2749 select => { aou => ["id","shortname", "name"]},
2754 return trim_tree($tree);
2760 return undef unless $tree;
2762 code => $tree->shortname,
2763 name => $tree->name,
2765 if( $tree->children and @{$tree->children} ) {
2766 $htree->{children} = [];
2767 for my $c (@{$tree->children}) {
2768 push( @{$htree->{children}}, trim_tree($c) );
2776 __PACKAGE__->register_method(
2777 method => "update_penalties",
2778 api_name => "open-ils.actor.user.penalties.update");
2779 sub update_penalties {
2780 my( $self, $conn, $auth, $userid ) = @_;
2781 my $e = new_editor(authtoken=>$auth);
2782 return $e->event unless $e->checkauth;
2783 $U->update_patron_penalties(
2785 patronid => $userid,
2792 __PACKAGE__->register_method(
2793 method => "user_retrieve_fleshed_by_id",
2794 api_name => "open-ils.actor.user.fleshed.retrieve",);
2796 sub user_retrieve_fleshed_by_id {
2797 my( $self, $client, $auth, $user_id, $fields ) = @_;
2798 my $e = new_editor(authtoken => $auth);
2799 return $e->event unless $e->checkauth;
2801 if( $e->requestor->id != $user_id ) {
2802 return $e->event unless $e->allowed('VIEW_USER');
2808 "standing_penalties",
2812 "stat_cat_entries" ];
2813 return new_flesh_user($user_id, $fields, $e);
2817 sub new_flesh_user {
2820 my $fields = shift || [];
2821 my $e = shift || new_editor(xact=>1);
2823 my $user = $e->retrieve_actor_user(
2828 "flesh_fields" => { "au" => $fields }
2831 ) or return $e->event;
2834 if( grep { $_ eq 'addresses' } @$fields ) {
2836 $user->addresses([]) unless @{$user->addresses};
2838 if( ref $user->billing_address ) {
2839 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2840 push( @{$user->addresses}, $user->billing_address );
2844 if( ref $user->mailing_address ) {
2845 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2846 push( @{$user->addresses}, $user->mailing_address );
2852 $user->clear_passwd();
2859 __PACKAGE__->register_method(
2860 method => "user_retrieve_parts",
2861 api_name => "open-ils.actor.user.retrieve.parts",);
2863 sub user_retrieve_parts {
2864 my( $self, $client, $auth, $user_id, $fields ) = @_;
2865 my $e = new_editor(authtoken => $auth);
2866 return $e->event unless $e->checkauth;
2867 if( $e->requestor->id != $user_id ) {
2868 return $e->event unless $e->allowed('VIEW_USER');
2871 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2872 push(@resp, $user->$_()) for(@$fields);