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 } );
2364 __PACKAGE__->register_method(
2365 method => "get_user_work_ous",
2366 api_name => "open-ils.actor.user.get_work_ous",
2367 notes => <<" NOTES");
2368 Retrieve a user's work org units.
2372 sub get_user_work_ous {
2373 my( $self, $client, $authtoken, $userid ) = @_;
2375 my( $requestor, $evt ) = $apputils->checksesperm( $authtoken, 'ASSIGN_WORK_ORG_UNIT' );
2376 return $evt if $evt;
2378 return $apputils->simplereq(
2380 'open-ils.cstore.direct.permission.usr_work_ou_map.search.atomic', { usr => $userid } );
2385 __PACKAGE__->register_method (
2386 method => 'register_workstation',
2387 api_name => 'open-ils.actor.workstation.register.override',
2388 signature => q/@see open-ils.actor.workstation.register/);
2390 __PACKAGE__->register_method (
2391 method => 'register_workstation',
2392 api_name => 'open-ils.actor.workstation.register',
2394 Registers a new workstion in the system
2395 @param authtoken The login session key
2396 @param name The name of the workstation id
2397 @param owner The org unit that owns this workstation
2398 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2399 if the name is already in use.
2402 sub _register_workstation {
2403 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2404 my( $requestor, $evt ) = $U->checkses($authtoken);
2405 return $evt if $evt;
2406 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2407 return $evt if $evt;
2409 my $ws = $U->cstorereq(
2410 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2411 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2413 $ws = Fieldmapper::actor::workstation->new;
2414 $ws->owning_lib($owner);
2417 my $id = $U->storagereq(
2418 'open-ils.storage.direct.actor.workstation.create', $ws );
2419 return $U->DB_UPDATE_FAILED($ws) unless $id;
2425 sub register_workstation {
2426 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2428 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2429 return $e->event unless $e->checkauth;
2430 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2431 my $existing = $e->search_actor_workstation({name => $name});
2434 if( $self->api_name =~ /override/o ) {
2435 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2436 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2438 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2442 my $ws = Fieldmapper::actor::workstation->new;
2443 $ws->owning_lib($owner);
2445 $e->create_actor_workstation($ws) or return $e->event;
2447 return $ws->id; # note: editor sets the id on the new object for us
2451 __PACKAGE__->register_method (
2452 method => 'fetch_patron_note',
2453 api_name => 'open-ils.actor.note.retrieve.all',
2455 Returns a list of notes for a given user
2456 Requestor must have VIEW_USER permission if pub==false and
2457 @param authtoken The login session key
2458 @param args Hash of params including
2459 patronid : the patron's id
2460 pub : true if retrieving only public notes
2464 sub fetch_patron_note {
2465 my( $self, $conn, $authtoken, $args ) = @_;
2466 my $patronid = $$args{patronid};
2468 my($reqr, $evt) = $U->checkses($authtoken);
2469 return $evt if $evt;
2472 ($patron, $evt) = $U->fetch_user($patronid);
2473 return $evt if $evt;
2476 if( $patronid ne $reqr->id ) {
2477 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2478 return $evt if $evt;
2480 return $U->cstorereq(
2481 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2482 { usr => $patronid, pub => 't' } );
2485 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2486 return $evt if $evt;
2488 return $U->cstorereq(
2489 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2492 __PACKAGE__->register_method (
2493 method => 'create_user_note',
2494 api_name => 'open-ils.actor.note.create',
2496 Creates a new note for the given user
2497 @param authtoken The login session key
2498 @param note The note object
2501 sub create_user_note {
2502 my( $self, $conn, $authtoken, $note ) = @_;
2503 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2504 return $e->die_event unless $e->checkauth;
2506 my $user = $e->retrieve_actor_user($note->usr)
2507 or return $e->die_event;
2509 return $e->die_event unless
2510 $e->allowed('UPDATE_USER',$user->home_ou);
2512 $note->creator($e->requestor->id);
2513 $e->create_actor_usr_note($note) or return $e->die_event;
2519 __PACKAGE__->register_method (
2520 method => 'delete_user_note',
2521 api_name => 'open-ils.actor.note.delete',
2523 Deletes a note for the given user
2524 @param authtoken The login session key
2525 @param noteid The note id
2528 sub delete_user_note {
2529 my( $self, $conn, $authtoken, $noteid ) = @_;
2531 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2532 return $e->die_event unless $e->checkauth;
2533 my $note = $e->retrieve_actor_usr_note($noteid)
2534 or return $e->die_event;
2535 my $user = $e->retrieve_actor_user($note->usr)
2536 or return $e->die_event;
2537 return $e->die_event unless
2538 $e->allowed('UPDATE_USER', $user->home_ou);
2540 $e->delete_actor_usr_note($note) or return $e->die_event;
2546 __PACKAGE__->register_method (
2547 method => 'update_user_note',
2548 api_name => 'open-ils.actor.note.update',
2550 @param authtoken The login session key
2551 @param note The note
2555 sub update_user_note {
2556 my( $self, $conn, $auth, $note ) = @_;
2557 my $e = new_editor(authtoken=>$auth, xact=>1);
2558 return $e->event unless $e->checkauth;
2559 my $patron = $e->retrieve_actor_user($note->usr)
2560 or return $e->event;
2561 return $e->event unless
2562 $e->allowed('UPDATE_USER', $patron->home_ou);
2563 $e->update_actor_user_note($note)
2564 or return $e->event;
2572 __PACKAGE__->register_method (
2573 method => 'create_closed_date',
2574 api_name => 'open-ils.actor.org_unit.closed_date.create',
2576 Creates a new closing entry for the given org_unit
2577 @param authtoken The login session key
2578 @param note The closed_date object
2581 sub create_closed_date {
2582 my( $self, $conn, $authtoken, $cd ) = @_;
2584 my( $user, $evt ) = $U->checkses($authtoken);
2585 return $evt if $evt;
2587 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2588 return $evt if $evt;
2590 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2592 my $id = $U->storagereq(
2593 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2594 return $U->DB_UPDATE_FAILED($cd) unless $id;
2599 __PACKAGE__->register_method (
2600 method => 'delete_closed_date',
2601 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2603 Deletes a closing entry for the given org_unit
2604 @param authtoken The login session key
2605 @param noteid The close_date id
2608 sub delete_closed_date {
2609 my( $self, $conn, $authtoken, $cd ) = @_;
2611 my( $user, $evt ) = $U->checkses($authtoken);
2612 return $evt if $evt;
2615 ($cd_obj, $evt) = fetch_closed_date($cd);
2616 return $evt if $evt;
2618 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2619 return $evt if $evt;
2621 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2623 my $stat = $U->storagereq(
2624 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2625 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2630 __PACKAGE__->register_method(
2631 method => 'usrname_exists',
2632 api_name => 'open-ils.actor.username.exists',
2634 Returns 1 if the requested username exists, returns 0 otherwise
2638 sub usrname_exists {
2639 my( $self, $conn, $auth, $usrname ) = @_;
2640 my $e = new_editor(authtoken=>$auth);
2641 return $e->event unless $e->checkauth;
2642 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2643 return $$a[0] if $a and @$a;
2647 __PACKAGE__->register_method(
2648 method => 'barcode_exists',
2649 api_name => 'open-ils.actor.barcode.exists',
2651 Returns 1 if the requested barcode exists, returns 0 otherwise
2655 sub barcode_exists {
2656 my( $self, $conn, $auth, $barcode ) = @_;
2657 my $e = new_editor(authtoken=>$auth);
2658 return $e->event unless $e->checkauth;
2659 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2660 return $$a[0] if $a and @$a;
2665 __PACKAGE__->register_method(
2666 method => 'retrieve_net_levels',
2667 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2670 sub retrieve_net_levels {
2671 my( $self, $conn, $auth ) = @_;
2672 my $e = new_editor(authtoken=>$auth);
2673 return $e->event unless $e->checkauth;
2674 return $e->retrieve_all_config_net_access_level();
2678 __PACKAGE__->register_method(
2679 method => 'fetch_org_by_shortname',
2680 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2682 sub fetch_org_by_shortname {
2683 my( $self, $conn, $sname ) = @_;
2684 my $e = new_editor();
2685 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2686 return $e->event unless $org;
2691 __PACKAGE__->register_method(
2692 method => 'session_home_lib',
2693 api_name => 'open-ils.actor.session.home_lib',
2696 sub session_home_lib {
2697 my( $self, $conn, $auth ) = @_;
2698 my $e = new_editor(authtoken=>$auth);
2699 return undef unless $e->checkauth;
2700 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2701 return $org->shortname;
2704 __PACKAGE__->register_method(
2705 method => 'session_safe_token',
2706 api_name => 'open-ils.actor.session.safe_token',
2708 Returns a hashed session ID that is safe for export to the world.
2709 This safe token will expire after 1 hour of non-use.
2710 @param auth Active authentication token
2714 sub session_safe_token {
2715 my( $self, $conn, $auth ) = @_;
2716 my $e = new_editor(authtoken=>$auth);
2717 return undef unless $e->checkauth;
2719 my $safe_token = md5_hex($auth);
2721 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2723 # Add more like the following if needed...
2725 "safe-token-home_lib-shortname-$safe_token",
2726 $e->retrieve_actor_org_unit(
2727 $e->requestor->home_ou
2736 __PACKAGE__->register_method(
2737 method => 'safe_token_home_lib',
2738 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2740 Returns the home library shortname from the session
2741 asscociated with a safe token from generated by
2742 open-ils.actor.session.safe_token.
2743 @param safe_token Active safe token
2747 sub safe_token_home_lib {
2748 my( $self, $conn, $safe_token ) = @_;
2750 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2751 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2756 __PACKAGE__->register_method(
2757 method => 'slim_tree',
2758 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2761 my $tree = new_editor()->search_actor_org_unit(
2763 {"parent_ou" => undef },
2766 flesh_fields => { aou => ['children'] },
2767 order_by => { aou => 'name'},
2768 select => { aou => ["id","shortname", "name"]},
2773 return trim_tree($tree);
2779 return undef unless $tree;
2781 code => $tree->shortname,
2782 name => $tree->name,
2784 if( $tree->children and @{$tree->children} ) {
2785 $htree->{children} = [];
2786 for my $c (@{$tree->children}) {
2787 push( @{$htree->{children}}, trim_tree($c) );
2795 __PACKAGE__->register_method(
2796 method => "update_penalties",
2797 api_name => "open-ils.actor.user.penalties.update");
2798 sub update_penalties {
2799 my( $self, $conn, $auth, $userid ) = @_;
2800 my $e = new_editor(authtoken=>$auth);
2801 return $e->event unless $e->checkauth;
2802 $U->update_patron_penalties(
2804 patronid => $userid,
2811 __PACKAGE__->register_method(
2812 method => "user_retrieve_fleshed_by_id",
2813 api_name => "open-ils.actor.user.fleshed.retrieve",);
2815 sub user_retrieve_fleshed_by_id {
2816 my( $self, $client, $auth, $user_id, $fields ) = @_;
2817 my $e = new_editor(authtoken => $auth);
2818 return $e->event unless $e->checkauth;
2820 if( $e->requestor->id != $user_id ) {
2821 return $e->event unless $e->allowed('VIEW_USER');
2827 "standing_penalties",
2831 "stat_cat_entries" ];
2832 return new_flesh_user($user_id, $fields, $e);
2836 sub new_flesh_user {
2839 my $fields = shift || [];
2840 my $e = shift || new_editor(xact=>1);
2842 my $user = $e->retrieve_actor_user(
2847 "flesh_fields" => { "au" => $fields }
2850 ) or return $e->event;
2853 if( grep { $_ eq 'addresses' } @$fields ) {
2855 $user->addresses([]) unless @{$user->addresses};
2857 if( ref $user->billing_address ) {
2858 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2859 push( @{$user->addresses}, $user->billing_address );
2863 if( ref $user->mailing_address ) {
2864 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2865 push( @{$user->addresses}, $user->mailing_address );
2871 $user->clear_passwd();
2878 __PACKAGE__->register_method(
2879 method => "user_retrieve_parts",
2880 api_name => "open-ils.actor.user.retrieve.parts",);
2882 sub user_retrieve_parts {
2883 my( $self, $client, $auth, $user_id, $fields ) = @_;
2884 my $e = new_editor(authtoken => $auth);
2885 return $e->event unless $e->checkauth;
2886 if( $e->requestor->id != $user_id ) {
2887 return $e->event unless $e->allowed('VIEW_USER');
2890 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2891 push(@resp, $user->$_()) for(@$fields);