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;
26 use OpenILS::Application::Actor::Container;
27 use OpenILS::Application::Actor::ClosedDates;
29 use OpenILS::Utils::CStoreEditor qw/:funcs/;
31 use OpenILS::Application::Actor::UserGroups;
33 OpenILS::Application::Actor::Container->initialize();
34 OpenILS::Application::Actor::UserGroups->initialize();
35 OpenILS::Application::Actor::ClosedDates->initialize();
38 my $apputils = "OpenILS::Application::AppUtils";
41 sub _d { warn "Patron:\n" . Dumper(shift()); }
46 my $set_user_settings;
49 __PACKAGE__->register_method(
50 method => "set_user_settings",
51 api_name => "open-ils.actor.patron.settings.update",
53 sub set_user_settings {
54 my( $self, $client, $user_session, $uid, $settings ) = @_;
56 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
58 my( $staff, $user, $evt ) =
59 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
63 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
65 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
67 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
69 return $apputils->simplereq(
71 'open-ils.storage.direct.actor.user_setting.batch.merge', @params );
77 __PACKAGE__->register_method(
78 method => "set_ou_settings",
79 api_name => "open-ils.actor.org_unit.settings.update",
82 my( $self, $client, $user_session, $ouid, $settings ) = @_;
84 my( $staff, $evt ) = $apputils->checkses( $user_session );
86 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
91 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
93 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
95 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper(\@params));
97 return $apputils->simplereq(
99 'open-ils.storage.direct.actor.org_unit_setting.merge', @params );
103 my $fetch_user_settings;
104 my $fetch_ou_settings;
106 __PACKAGE__->register_method(
107 method => "user_settings",
108 api_name => "open-ils.actor.patron.settings.retrieve",
111 my( $self, $client, $user_session, $uid ) = @_;
113 my( $staff, $user, $evt ) =
114 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
117 $logger->debug("User " . $staff->id . " fetching user $uid\n");
118 my $s = $apputils->simplereq(
120 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
122 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
127 __PACKAGE__->register_method(
128 method => "ou_settings",
129 api_name => "open-ils.actor.org_unit.settings.retrieve",
132 my( $self, $client, $ouid ) = @_;
134 $logger->info("Fetching org unit settings for org $ouid");
136 my $s = $apputils->simplereq(
138 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
140 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
143 __PACKAGE__->register_method (
144 method => "ou_setting_delete",
145 api_name => 'open-ils.actor.org_setting.delete',
147 Deletes a specific org unit setting for a specific location
148 @param authtoken The login session key
149 @param orgid The org unit whose setting we're changing
150 @param setting The name of the setting to delete
151 @return True value on success.
155 sub ou_setting_delete {
156 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
157 my( $reqr, $evt) = $U->checkses($authtoken);
159 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
162 my $id = $U->cstorereq(
163 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
164 { name => $setting, org_unit => $orgid } );
166 $logger->debug("Retrieved setting $id in org unit setting delete");
168 my $s = $U->cstorereq(
169 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
171 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
177 __PACKAGE__->register_method(
178 method => "update_patron",
179 api_name => "open-ils.actor.patron.update",);
182 my( $self, $client, $user_session, $patron ) = @_;
184 my $session = $apputils->start_db_session();
187 $logger->info("Creating new patron...") if $patron->isnew;
188 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
190 my( $user_obj, $evt ) = $U->checkses($user_session);
193 # XXX does this user have permission to add/create users. Granularity?
194 # $new_patron is the patron in progress. $patron is the original patron
195 # passed in with the method. new_patron will change as the components
196 # of patron are added/updated.
200 # unflesh the real items on the patron
201 $patron->card( $patron->card->id ) if(ref($patron->card));
202 $patron->billing_address( $patron->billing_address->id )
203 if(ref($patron->billing_address));
204 $patron->mailing_address( $patron->mailing_address->id )
205 if(ref($patron->mailing_address));
207 # create/update the patron first so we can use his id
208 if($patron->isnew()) {
209 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
211 } else { $new_patron = $patron; }
213 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
216 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
219 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
222 # re-update the patron if anything has happened to him during this process
223 if($new_patron->ischanged()) {
224 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
228 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
230 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
233 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
236 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
239 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
240 $apputils->commit_db_session($session);
242 #warn "Patron Update/Create complete\n";
243 return flesh_user($new_patron->id());
249 __PACKAGE__->register_method(
250 method => "user_retrieve_fleshed_by_id",
251 api_name => "open-ils.actor.user.fleshed.retrieve",);
253 sub user_retrieve_fleshed_by_id {
254 my( $self, $client, $user_session, $user_id ) = @_;
256 my( $requestor, $target, $evt ) = $apputils->
257 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
260 return flesh_user($user_id);
264 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
273 $session = OpenSRF::AppSession->create("open-ils.storage");
277 # grab the user with the given id
278 my $ureq = $session->request(
279 "open-ils.storage.direct.actor.user.retrieve", $id);
280 my $user = $ureq->gather(1);
282 if(!$user) { return undef; }
285 my $cards_req = $session->request(
286 "open-ils.storage.direct.actor.card.search.usr.atomic",
288 $user->cards( $cards_req->gather(1) );
290 for my $c(@{$user->cards}) {
291 if($c->id == $user->card || $c->id eq $user->card ) {
292 #warn "Setting my card to " . $c->id . "\n";
297 my $add_req = $session->request(
298 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
300 $user->addresses( $add_req->gather(1) );
302 if( @{$user->addresses} ) {
303 if( ! grep { $_->id eq $user->billing_address } @{$user->addresses} ) {
304 my $ba = $session->request(
305 'open-ils.storage.direct.actor.user_address.retrieve',
306 $user->billing_address)->gather(1);
307 push( @{$user->addresses}, $ba );
310 if( ! grep { $_->id eq $user->mailing_address } @{$user->addresses} ) {
311 my $ba = $session->request(
312 'open-ils.storage.direct.actor.user_address.retrieve',
313 $user->mailing_address)->gather(1);
314 push( @{$user->addresses}, $ba );
319 for my $c(@{$user->addresses}) {
320 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
321 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
324 my $stat_req = $session->request(
325 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
327 $user->stat_cat_entries($stat_req->gather(1));
329 my $standing_penalties_req = $session->request(
330 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
332 $user->standing_penalties($standing_penalties_req->gather(1));
334 if($kill) { $session->disconnect(); }
335 $user->clear_passwd();
342 my $e = new_editor();
343 my $user = $e->retrieve_actor_user(
352 "standing_penalties",
361 ) or return $e->event;
363 $user->clear_passwd();
372 # clone and clear stuff that would break the database
376 my $new_patron = $patron->clone;
378 # Using the Fieldmapper clone method
379 #my $new_patron = Fieldmapper::actor::user->new();
381 #my $fmap = $Fieldmapper::fieldmap;
382 #no strict; # shallow clone, may be useful in the fieldmapper
384 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
385 # $new_patron->$field( $patron->$field() );
390 $new_patron->clear_billing_address();
391 $new_patron->clear_mailing_address();
392 $new_patron->clear_addresses();
393 $new_patron->clear_card();
394 $new_patron->clear_cards();
395 $new_patron->clear_id();
396 $new_patron->clear_isnew();
397 $new_patron->clear_ischanged();
398 $new_patron->clear_isdeleted();
399 $new_patron->clear_stat_cat_entries();
400 $new_patron->clear_permissions();
401 $new_patron->clear_standing_penalties();
411 my $user_obj = shift;
413 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
414 return (undef, $evt) if $evt;
416 my $ex = $session->request(
417 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
419 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
422 $evt = _check_dup_ident($session, $patron);
423 return (undef, $evt) if $evt;
425 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
427 my $id = $session->request(
428 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
429 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
431 $logger->info("Successfully created new user [$id] in DB");
433 return ( $session->request(
434 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
439 my( $session, $patron, $user_obj, $noperm) = @_;
441 $logger->info("Updating patron ".$patron->id." in DB");
446 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
447 return (undef, $evt) if $evt;
450 $evt = _check_dup_ident($session, $patron);
451 return (undef, $evt) if $evt;
454 # update the password by itself to avoid the password protection magic
455 if( $patron->passwd ) {
456 my $s = $session->request(
457 'open-ils.storage.direct.actor.user.remote_update',
458 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
459 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
460 $patron->clear_passwd;
463 if(!$patron->ident_type) {
464 $patron->clear_ident_type;
465 $patron->clear_ident_value;
468 if(!$patron->ident_type2) {
469 $patron->clear_ident_type2;
470 $patron->clear_ident_value2;
473 my $stat = $session->request(
474 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
475 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
480 sub _check_dup_ident {
481 my( $session, $patron ) = @_;
483 return undef unless $patron->ident_value;
486 ident_type => $patron->ident_type,
487 ident_value => $patron->ident_value,
490 $logger->debug("patron update searching for dup ident values: " .
491 $patron->ident_type . ':' . $patron->ident_value);
493 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
495 my $dups = $session->request(
496 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
499 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
506 sub _add_update_addresses {
510 my $new_patron = shift;
514 my $current_id; # id of the address before creation
516 for my $address (@{$patron->addresses()}) {
518 next unless ref $address;
519 $current_id = $address->id();
521 if( $patron->billing_address() and
522 $patron->billing_address() == $current_id ) {
523 $logger->info("setting billing addr to $current_id");
524 $new_patron->billing_address($address->id());
525 $new_patron->ischanged(1);
528 if( $patron->mailing_address() and
529 $patron->mailing_address() == $current_id ) {
530 $new_patron->mailing_address($address->id());
531 $logger->info("setting mailing addr to $current_id");
532 $new_patron->ischanged(1);
536 if($address->isnew()) {
538 $address->usr($new_patron->id());
540 ($address, $evt) = _add_address($session,$address);
541 return (undef, $evt) if $evt;
543 # we need to get the new id
544 if( $patron->billing_address() and
545 $patron->billing_address() == $current_id ) {
546 $new_patron->billing_address($address->id());
547 $logger->info("setting billing addr to $current_id");
548 $new_patron->ischanged(1);
551 if( $patron->mailing_address() and
552 $patron->mailing_address() == $current_id ) {
553 $new_patron->mailing_address($address->id());
554 $logger->info("setting mailing addr to $current_id");
555 $new_patron->ischanged(1);
558 } elsif($address->ischanged() ) {
560 ($address, $evt) = _update_address($session, $address);
561 return (undef, $evt) if $evt;
563 } elsif($address->isdeleted() ) {
565 if( $address->id() == $new_patron->mailing_address() ) {
566 $new_patron->clear_mailing_address();
567 ($new_patron, $evt) = _update_patron($session, $new_patron);
568 return (undef, $evt) if $evt;
571 if( $address->id() == $new_patron->billing_address() ) {
572 $new_patron->clear_billing_address();
573 ($new_patron, $evt) = _update_patron($session, $new_patron);
574 return (undef, $evt) if $evt;
577 $evt = _delete_address($session, $address);
578 return (undef, $evt) if $evt;
582 return ( $new_patron, undef );
586 # adds an address to the db and returns the address with new id
588 my($session, $address) = @_;
589 $address->clear_id();
591 $logger->info("Creating new address at street ".$address->street1);
593 # put the address into the database
594 my $id = $session->request(
595 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
596 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
599 return ($address, undef);
603 sub _update_address {
604 my( $session, $address ) = @_;
606 $logger->info("Updating address ".$address->id." in the DB");
608 my $stat = $session->request(
609 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
611 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
612 return ($address, undef);
617 sub _add_update_cards {
621 my $new_patron = shift;
625 my $virtual_id; #id of the card before creation
626 for my $card (@{$patron->cards()}) {
628 $card->usr($new_patron->id());
630 if(ref($card) and $card->isnew()) {
632 $virtual_id = $card->id();
633 ( $card, $evt ) = _add_card($session,$card);
634 return (undef, $evt) if $evt;
636 #if(ref($patron->card)) { $patron->card($patron->card->id); }
637 if($patron->card() == $virtual_id) {
638 $new_patron->card($card->id());
639 $new_patron->ischanged(1);
642 } elsif( ref($card) and $card->ischanged() ) {
643 $evt = _update_card($session, $card);
644 return (undef, $evt) if $evt;
648 return ( $new_patron, undef );
652 # adds an card to the db and returns the card with new id
654 my( $session, $card ) = @_;
657 $logger->info("Adding new patron card ".$card->barcode);
659 my $id = $session->request(
660 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
661 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
662 $logger->info("Successfully created patron card $id");
665 return ( $card, undef );
669 # returns event on error. returns undef otherwise
671 my( $session, $card ) = @_;
672 $logger->info("Updating patron card ".$card->id);
674 my $stat = $session->request(
675 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
676 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
683 # returns event on error. returns undef otherwise
684 sub _delete_address {
685 my( $session, $address ) = @_;
687 $logger->info("Deleting address ".$address->id." from DB");
689 my $stat = $session->request(
690 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
692 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
698 sub _add_survey_responses {
699 my ($session, $patron, $new_patron) = @_;
701 $logger->info( "Updating survey responses for patron ".$new_patron->id );
703 my $responses = $patron->survey_responses;
707 $_->usr($new_patron->id) for (@$responses);
709 my $evt = $U->simplereq( "open-ils.circ",
710 "open-ils.circ.survey.submit.user_id", $responses );
712 return (undef, $evt) if defined($U->event_code($evt));
716 return ( $new_patron, undef );
720 sub _create_stat_maps {
722 my($session, $user_session, $patron, $new_patron) = @_;
724 my $maps = $patron->stat_cat_entries();
726 for my $map (@$maps) {
728 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
730 if ($map->isdeleted()) {
731 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
733 } elsif ($map->isnew()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
739 $map->target_usr($new_patron->id);
742 $logger->info("Updating stat entry with method $method and map $map");
744 my $stat = $session->request($method, $map)->gather(1);
745 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
749 return ($new_patron, undef);
752 sub _create_perm_maps {
754 my($session, $user_session, $patron, $new_patron) = @_;
756 my $maps = $patron->permissions;
758 for my $map (@$maps) {
760 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
761 if ($map->isdeleted()) {
762 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
763 } elsif ($map->isnew()) {
764 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
769 $map->usr($new_patron->id);
771 #warn( "Updating permissions with method $method and session $user_session and map $map" );
772 $logger->info( "Updating permissions with method $method and map $map" );
774 my $stat = $session->request($method, $map)->gather(1);
775 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
779 return ($new_patron, undef);
783 sub _create_standing_penalties {
785 my($session, $user_session, $patron, $new_patron) = @_;
787 my $maps = $patron->standing_penalties;
790 for my $map (@$maps) {
792 if ($map->isdeleted()) {
793 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
794 } elsif ($map->isnew()) {
795 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
801 $map->usr($new_patron->id);
803 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
805 my $stat = $session->request($method, $map)->gather(1);
806 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
809 return ($new_patron, undef);
814 __PACKAGE__->register_method(
815 method => "search_username",
816 api_name => "open-ils.actor.user.search.username",
819 sub search_username {
820 my($self, $client, $username) = @_;
821 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
823 "open-ils.cstore.direct.actor.user.search.atomic",
824 { usrname => $username }
832 __PACKAGE__->register_method(
833 method => "user_retrieve_by_barcode",
834 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
836 sub user_retrieve_by_barcode {
837 my($self, $client, $user_session, $barcode) = @_;
839 $logger->debug("Searching for user with barcode $barcode");
840 my ($user_obj, $evt) = $apputils->checkses($user_session);
843 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
845 "open-ils.cstore.direct.actor.card.search.atomic",
846 { barcode => $barcode },
848 flesh_fields => { ac => [ 'usr' ] }
852 if(!$card || !$card->[0]) {
853 $session->disconnect();
854 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
858 my $user = flesh_user($card->usr(), $session);
860 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
863 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
870 __PACKAGE__->register_method(
871 method => "get_user_by_id",
872 api_name => "open-ils.actor.user.retrieve",);
875 my ($self, $client, $auth, $id) = @_;
876 my $e = new_editor(authtoken=>$auth);
877 return $e->event unless $e->checkauth;
878 my $user = $e->retrieve_actor_user($id)
880 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
886 __PACKAGE__->register_method(
887 method => "get_org_types",
888 api_name => "open-ils.actor.org_types.retrieve",);
892 my($self, $client) = @_;
893 return $org_types if $org_types;
894 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
899 __PACKAGE__->register_method(
900 method => "get_user_profiles",
901 api_name => "open-ils.actor.user.profiles.retrieve",
905 sub get_user_profiles {
906 return $user_profiles if $user_profiles;
908 return $user_profiles =
909 $apputils->simple_scalar_request(
911 "open-ils.cstore.direct.actor.profile.search.atomic", { id => { "!=" => undef });
916 __PACKAGE__->register_method(
917 method => "get_user_ident_types",
918 api_name => "open-ils.actor.user.ident_types.retrieve",
921 sub get_user_ident_types {
922 return $ident_types if $ident_types;
923 return $ident_types =
924 new_editor()->retrieve_all_config_identification_type();
930 __PACKAGE__->register_method(
931 method => "get_org_unit",
932 api_name => "open-ils.actor.org_unit.retrieve",
936 my( $self, $client, $user_session, $org_id ) = @_;
937 my $e = new_editor(authtoken => $user_session);
939 return $e->event unless $e->checkauth;
940 $org_id = $e->requestor->ws_ou;
942 my $o = $e->retrieve_actor_org_unit($org_id)
947 __PACKAGE__->register_method(
948 method => "search_org_unit",
949 api_name => "open-ils.actor.org_unit_list.search",
952 sub search_org_unit {
954 my( $self, $client, $field, $value ) = @_;
956 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
958 "open-ils.cstore.direct.actor.org_unit.search.atomic",
959 { $field => $value } );
967 __PACKAGE__->register_method(
968 method => "get_org_tree",
969 api_name => "open-ils.actor.org_tree.retrieve",
971 note => "Returns the entire org tree structure",
975 my( $self, $client) = @_;
977 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
978 my $tree = $cache->get_cache('orgtree');
979 return $tree if $tree;
981 $tree = new_editor()->search_actor_org_unit(
983 {"parent_ou" => undef },
986 flesh_fields => { aou => ['children'] },
987 order_by => { aou => 'name'}
992 $cache->put_cache('orgtree', $tree);
997 # turns an org list into an org tree
1000 my( $self, $orglist) = @_;
1002 return $orglist unless (
1003 ref($orglist) and @$orglist > 1 );
1006 $a->ou_type <=> $b->ou_type ||
1007 $a->name cmp $b->name } @$orglist;
1009 for my $org (@list) {
1011 next unless ($org and defined($org->parent_ou));
1012 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1013 next unless $parent;
1015 $parent->children([]) unless defined($parent->children);
1016 push( @{$parent->children}, $org );
1024 __PACKAGE__->register_method(
1025 method => "get_org_descendants",
1026 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1029 # depth is optional. org_unit is the id
1030 sub get_org_descendants {
1031 my( $self, $client, $org_unit, $depth ) = @_;
1032 my $orglist = $apputils->simple_scalar_request(
1034 "open-ils.storage.actor.org_unit.descendants.atomic",
1035 $org_unit, $depth );
1036 return $self->build_org_tree($orglist);
1040 __PACKAGE__->register_method(
1041 method => "get_org_ancestors",
1042 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1045 # depth is optional. org_unit is the id
1046 sub get_org_ancestors {
1047 my( $self, $client, $org_unit, $depth ) = @_;
1048 my $orglist = $apputils->simple_scalar_request(
1050 "open-ils.storage.actor.org_unit.ancestors.atomic",
1051 $org_unit, $depth );
1052 return $self->build_org_tree($orglist);
1056 __PACKAGE__->register_method(
1057 method => "get_standings",
1058 api_name => "open-ils.actor.standings.retrieve"
1063 return $user_standings if $user_standings;
1064 return $user_standings =
1065 $apputils->simple_scalar_request(
1067 "open-ils.cstore.direct.config.standing.search.atomic",
1068 { id => { "!=" => undef } }
1074 __PACKAGE__->register_method(
1075 method => "get_my_org_path",
1076 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1079 sub get_my_org_path {
1080 my( $self, $client, $user_session, $org_id ) = @_;
1081 my $user_obj = $apputils->check_user_session($user_session);
1082 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1084 return $apputils->simple_scalar_request(
1086 "open-ils.storage.actor.org_unit.full_path.atomic",
1091 __PACKAGE__->register_method(
1092 method => "patron_adv_search",
1093 api_name => "open-ils.actor.patron.search.advanced" );
1094 sub patron_adv_search {
1095 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1096 my $e = new_editor(authtoken=>$auth);
1097 return $e->event unless $e->checkauth;
1098 return $e->event unless $e->allowed('VIEW_USER');
1099 return $U->storagereq(
1100 "open-ils.storage.actor.user.crazy_search",
1101 $search_hash, $search_limit, $search_sort);
1106 sub _verify_password {
1107 my($user_session, $password) = @_;
1108 my $user_obj = $apputils->check_user_session($user_session);
1110 #grab the user with password
1111 $user_obj = $apputils->simple_scalar_request(
1113 "open-ils.cstore.direct.actor.user.retrieve",
1116 if($user_obj->passwd eq $password) {
1124 __PACKAGE__->register_method(
1125 method => "update_password",
1126 api_name => "open-ils.actor.user.password.update");
1128 __PACKAGE__->register_method(
1129 method => "update_password",
1130 api_name => "open-ils.actor.user.username.update");
1132 __PACKAGE__->register_method(
1133 method => "update_password",
1134 api_name => "open-ils.actor.user.email.update");
1136 sub update_password {
1137 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1141 my $user_obj = $apputils->check_user_session($user_session);
1143 if($self->api_name =~ /password/o) {
1145 #make sure they know the current password
1146 if(!_verify_password($user_session, md5_hex($current_password))) {
1147 return OpenILS::Event->new('INCORRECT_PASSWORD');
1150 $logger->debug("update_password setting new password $new_value");
1151 $user_obj->passwd($new_value);
1153 } elsif($self->api_name =~ /username/o) {
1154 my $users = search_username(undef, undef, $new_value);
1155 if( $users and $users->[0] ) {
1156 return OpenILS::Event->new('USERNAME_EXISTS');
1158 $user_obj->usrname($new_value);
1160 } elsif($self->api_name =~ /email/o) {
1161 #warn "Updating email to $new_value\n";
1162 $user_obj->email($new_value);
1165 my $session = $apputils->start_db_session();
1167 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1168 return $evt if $evt;
1170 $apputils->commit_db_session($session);
1172 if($user_obj) { return 1; }
1177 __PACKAGE__->register_method(
1178 method => "check_user_perms",
1179 api_name => "open-ils.actor.user.perm.check",
1180 notes => <<" NOTES");
1181 Takes a login session, user id, an org id, and an array of perm type strings. For each
1182 perm type, if the user does *not* have the given permission it is added
1183 to a list which is returned from the method. If all permissions
1184 are allowed, an empty list is returned
1185 if the logged in user does not match 'user_id', then the logged in user must
1186 have VIEW_PERMISSION priveleges.
1189 sub check_user_perms {
1190 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1192 my( $staff, $evt ) = $apputils->checkses($login_session);
1193 return $evt if $evt;
1195 if($staff->id ne $user_id) {
1196 if( my $evt = $apputils->check_perms(
1197 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1203 for my $perm (@$perm_types) {
1204 if($apputils->check_perms($user_id, $org_id, $perm)) {
1205 push @not_allowed, $perm;
1209 return \@not_allowed
1212 __PACKAGE__->register_method(
1213 method => "check_user_perms2",
1214 api_name => "open-ils.actor.user.perm.check.multi_org",
1216 Checks the permissions on a list of perms and orgs for a user
1217 @param authtoken The login session key
1218 @param user_id The id of the user to check
1219 @param orgs The array of org ids
1220 @param perms The array of permission names
1221 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1222 if the logged in user does not match 'user_id', then the logged in user must
1223 have VIEW_PERMISSION priveleges.
1226 sub check_user_perms2 {
1227 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1229 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1230 $authtoken, $user_id, 'VIEW_PERMISSION' );
1231 return $evt if $evt;
1234 for my $org (@$orgs) {
1235 for my $perm (@$perms) {
1236 if($apputils->check_perms($user_id, $org, $perm)) {
1237 push @not_allowed, [ $org, $perm ];
1242 return \@not_allowed
1246 __PACKAGE__->register_method(
1247 method => 'check_user_perms3',
1248 api_name => 'open-ils.actor.user.perm.highest_org',
1250 Returns the highest org unit id at which a user has a given permission
1251 If the requestor does not match the target user, the requestor must have
1252 'VIEW_PERMISSION' rights at the home org unit of the target user
1253 @param authtoken The login session key
1254 @param userid The id of the user in question
1255 @param perm The permission to check
1256 @return The org unit highest in the org tree within which the user has
1257 the requested permission
1260 sub check_user_perms3 {
1261 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1263 my( $staff, $target, $org, $evt );
1265 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1266 $authtoken, $userid, 'VIEW_PERMISSION' );
1267 return $evt if $evt;
1269 my $tree = $self->get_org_tree();
1270 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1274 sub _find_highest_perm_org {
1275 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1276 my $org = $apputils->find_org($org_tree, $start_org );
1280 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1282 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1288 __PACKAGE__->register_method(
1289 method => 'check_user_perms4',
1290 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1292 Returns the highest org unit id at which a user has a given permission
1293 If the requestor does not match the target user, the requestor must have
1294 'VIEW_PERMISSION' rights at the home org unit of the target user
1295 @param authtoken The login session key
1296 @param userid The id of the user in question
1297 @param perms An array of perm names to check
1298 @return An array of orgId's representing the org unit
1299 highest in the org tree within which the user has the requested permission
1300 The arrah of orgId's has matches the order of the perms array
1303 sub check_user_perms4 {
1304 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1306 my( $staff, $target, $org, $evt );
1308 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1309 $authtoken, $userid, 'VIEW_PERMISSION' );
1310 return $evt if $evt;
1313 return [] unless ref($perms);
1314 my $tree = $self->get_org_tree();
1316 for my $p (@$perms) {
1317 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1325 __PACKAGE__->register_method(
1326 method => "user_fines_summary",
1327 api_name => "open-ils.actor.user.fines.summary",
1328 notes => <<" NOTES");
1329 Returns a short summary of the users total open fines, excluding voided fines
1330 Params are login_session, user_id
1331 Returns a 'mous' object.
1334 sub user_fines_summary {
1335 my( $self, $client, $login_session, $user_id ) = @_;
1337 my $user_obj = $apputils->check_user_session($login_session);
1338 if($user_obj->id ne $user_id) {
1339 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1340 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1344 return $apputils->simple_scalar_request(
1346 "open-ils.cstore.direct.money.open_user_summary.search",
1347 { usr => $user_id } );
1354 __PACKAGE__->register_method(
1355 method => "user_transactions",
1356 api_name => "open-ils.actor.user.transactions",
1357 notes => <<" NOTES");
1358 Returns a list of open user transactions (mbts objects);
1359 Params are login_session, user_id
1360 Optional third parameter is the transactions type. defaults to all
1363 __PACKAGE__->register_method(
1364 method => "user_transactions",
1365 api_name => "open-ils.actor.user.transactions.have_charge",
1366 notes => <<" NOTES");
1367 Returns a list of all open user transactions (mbts objects) that have an initial charge
1368 Params are login_session, user_id
1369 Optional third parameter is the transactions type. defaults to all
1372 __PACKAGE__->register_method(
1373 method => "user_transactions",
1374 api_name => "open-ils.actor.user.transactions.have_balance",
1375 notes => <<" NOTES");
1376 Returns a list of all open user transactions (mbts objects) that have a balance
1377 Params are login_session, user_id
1378 Optional third parameter is the transactions type. defaults to all
1381 __PACKAGE__->register_method(
1382 method => "user_transactions",
1383 api_name => "open-ils.actor.user.transactions.fleshed",
1384 notes => <<" NOTES");
1385 Returns an object/hash of transaction, circ, title where transaction = an open
1386 user transactions (mbts objects), circ is the attached circluation, and title
1387 is the title the circ points to
1388 Params are login_session, user_id
1389 Optional third parameter is the transactions type. defaults to all
1392 __PACKAGE__->register_method(
1393 method => "user_transactions",
1394 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1395 notes => <<" NOTES");
1396 Returns an object/hash of transaction, circ, title where transaction = an open
1397 user transactions that has an initial charge (mbts objects), circ is the
1398 attached circluation, and title is the title the circ points to
1399 Params are login_session, user_id
1400 Optional third parameter is the transactions type. defaults to all
1403 __PACKAGE__->register_method(
1404 method => "user_transactions",
1405 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1406 notes => <<" NOTES");
1407 Returns an object/hash of transaction, circ, title where transaction = an open
1408 user transaction that has a balance (mbts objects), circ is the attached
1409 circluation, and title is the title the circ points to
1410 Params are login_session, user_id
1411 Optional third parameter is the transaction type. defaults to all
1414 __PACKAGE__->register_method(
1415 method => "user_transactions",
1416 api_name => "open-ils.actor.user.transactions.count",
1417 notes => <<" NOTES");
1418 Returns an object/hash of transaction, circ, title where transaction = an open
1419 user transactions (mbts objects), circ is the attached circluation, and title
1420 is the title the circ points to
1421 Params are login_session, user_id
1422 Optional third parameter is the transactions type. defaults to all
1425 __PACKAGE__->register_method(
1426 method => "user_transactions",
1427 api_name => "open-ils.actor.user.transactions.have_charge.count",
1428 notes => <<" NOTES");
1429 Returns an object/hash of transaction, circ, title where transaction = an open
1430 user transactions that has an initial charge (mbts objects), circ is the
1431 attached circluation, and title is the title the circ points to
1432 Params are login_session, user_id
1433 Optional third parameter is the transactions type. defaults to all
1436 __PACKAGE__->register_method(
1437 method => "user_transactions",
1438 api_name => "open-ils.actor.user.transactions.have_balance.count",
1439 notes => <<" NOTES");
1440 Returns an object/hash of transaction, circ, title where transaction = an open
1441 user transaction that has a balance (mbts objects), circ is the attached
1442 circluation, and title is the title the circ points to
1443 Params are login_session, user_id
1444 Optional third parameter is the transaction type. defaults to all
1447 __PACKAGE__->register_method(
1448 method => "user_transactions",
1449 api_name => "open-ils.actor.user.transactions.have_balance.total",
1450 notes => <<" NOTES");
1451 Returns an object/hash of transaction, circ, title where transaction = an open
1452 user transaction that has a balance (mbts objects), circ is the attached
1453 circluation, and title is the title the circ points to
1454 Params are login_session, user_id
1455 Optional third parameter is the transaction type. defaults to all
1460 sub user_transactions {
1461 my( $self, $client, $login_session, $user_id, $type ) = @_;
1463 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1464 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1465 return $evt if $evt;
1467 my $api = $self->api_name();
1471 if(defined($type)) { @xact = (xact_type => $type);
1473 } else { @xact = (); }
1475 if($api =~ /have_charge/o) {
1477 $trans = $apputils->simple_scalar_request(
1479 "open-ils.cstore.direct.money.open_billable_transaction_summary.search.atomic",
1480 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1482 } elsif($api =~ /have_balance/o) {
1484 $trans = $apputils->simple_scalar_request(
1486 "open-ils.cstore.direct.money.open_billable_transaction_summary.search.atomic",
1487 { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1491 $trans = $apputils->simple_scalar_request(
1493 "open-ils.cstore.direct.money.open_billable_transaction_summary.search.atomic",
1494 { usr => $user_id, @xact });
1497 if($api =~ /total/o) {
1499 for my $t (@$trans) {
1500 $total += $t->balance_owed;
1503 $logger->debug("Total balance owed by user $user_id: $total");
1507 if($api =~ /count/o) { return scalar @$trans; }
1508 if($api !~ /fleshed/o) { return $trans; }
1511 for my $t (@$trans) {
1513 if( $t->xact_type ne 'circulation' ) {
1514 push @resp, {transaction => $t};
1518 my $circ = $apputils->simple_scalar_request(
1520 "open-ils.cstore.direct.action.circulation.retrieve",
1525 my $title = $apputils->simple_scalar_request(
1527 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1528 $circ->target_copy );
1532 my $u = OpenILS::Utils::ModsParser->new();
1533 $u->start_mods_batch($title->marc());
1534 my $mods = $u->finish_mods_batch();
1536 push @resp, {transaction => $t, circ => $circ, record => $mods };
1544 __PACKAGE__->register_method(
1545 method => "user_transaction_retrieve",
1546 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1548 notes => <<" NOTES");
1549 Returns a fleshedtransaction record
1551 __PACKAGE__->register_method(
1552 method => "user_transaction_retrieve",
1553 api_name => "open-ils.actor.user.transaction.retrieve",
1555 notes => <<" NOTES");
1556 Returns a transaction record
1558 sub user_transaction_retrieve {
1559 my( $self, $client, $login_session, $bill_id ) = @_;
1561 my $trans = $apputils->simple_scalar_request(
1563 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1567 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1568 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1569 return $evt if $evt;
1571 my $api = $self->api_name();
1572 if($api !~ /fleshed/o) { return $trans; }
1574 if( $trans->xact_type ne 'circulation' ) {
1575 $logger->debug("Returning non-circ transaction");
1576 return {transaction => $trans};
1579 my $circ = $apputils->simple_scalar_request(
1581 "open-ils..direct.action.circulation.retrieve",
1584 return {transaction => $trans} unless $circ;
1585 $logger->debug("Found the circ transaction");
1587 my $title = $apputils->simple_scalar_request(
1589 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1590 $circ->target_copy );
1592 return {transaction => $trans, circ => $circ } unless $title;
1593 $logger->debug("Found the circ title");
1597 my $u = OpenILS::Utils::ModsParser->new();
1598 $u->start_mods_batch($title->marc());
1599 $mods = $u->finish_mods_batch();
1601 if ($title->id == -1) {
1602 my $copy = $apputils->simple_scalar_request(
1604 "open-ils.cstore.direct.asset.copy.retrieve",
1605 $circ->target_copy );
1607 $mods = new Fieldmapper::metabib::virtual_record;
1609 $mods->title($copy->dummy_title);
1610 $mods->author($copy->dummy_author);
1614 $logger->debug("MODSized the circ title");
1616 return {transaction => $trans, circ => $circ, record => $mods };
1620 __PACKAGE__->register_method(
1621 method => "hold_request_count",
1622 api_name => "open-ils.actor.user.hold_requests.count",
1624 notes => <<" NOTES");
1625 Returns hold ready/total counts
1627 sub hold_request_count {
1628 my( $self, $client, $login_session, $userid ) = @_;
1630 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1631 $login_session, $userid, 'VIEW_HOLD' );
1632 return $evt if $evt;
1635 my $holds = $apputils->simple_scalar_request(
1637 "open-ils.cstore.direct.action.hold_request.search.atomic",
1639 fulfillment_time => {"=" => undef } }
1643 for my $h (@$holds) {
1644 next unless $h->capture_time;
1646 my $copy = $apputils->simple_scalar_request(
1648 "open-ils.cstore.direct.asset.copy.retrieve",
1652 if ($copy->status == 8) {
1657 return { total => scalar(@$holds), ready => scalar(@ready) };
1661 __PACKAGE__->register_method(
1662 method => "checkedout_count",
1663 api_name => "open-ils.actor.user.checked_out.count__",
1665 notes => <<" NOTES");
1666 Returns a transaction record
1670 sub checkedout_count {
1671 my( $self, $client, $login_session, $userid ) = @_;
1673 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1674 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1675 return $evt if $evt;
1677 my $circs = $apputils->simple_scalar_request(
1679 "open-ils.cstore.direct.action.circulation.search.atomic",
1680 { usr => $userid, stop_fines => undef }
1681 #{ usr => $userid, checkin_time => {"=" => undef } }
1684 my $parser = DateTime::Format::ISO8601->new;
1687 for my $c (@$circs) {
1688 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1689 my $due = $due_dt->epoch;
1691 if ($due < DateTime->today->epoch) {
1696 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1700 __PACKAGE__->register_method(
1701 method => "checked_out",
1702 api_name => "open-ils.actor.user.checked_out",
1705 Returns a structure of circulations objects sorted by
1706 out, overdue, lost, claims_returned, long_overdue.
1707 A list of IDs are returned of each type.
1708 lost, long_overdue, and claims_returned circ will not
1709 be "finished" (there is an outstanding balance or some
1710 other pending action on the circ).
1712 The .count method also includes a 'total' field which
1713 sums all "open" circs
1717 __PACKAGE__->register_method(
1718 method => "checked_out",
1719 api_name => "open-ils.actor.user.checked_out.count",
1721 signature => q/@see open-ils.actor.user.checked_out/
1725 my( $self, $conn, $auth, $userid ) = @_;
1727 my $e = new_editor(authtoken=>$auth);
1728 return $e->event unless $e->checkauth;
1730 if( $userid ne $e->requestor->id ) {
1731 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1734 my $count = $self->api_name =~ /count/;
1735 return _checked_out( $count, $e, $userid );
1739 my( $iscount, $e, $userid ) = @_;
1741 my $circs = $e->search_action_circulation(
1742 { usr => $userid, stop_fines => undef });
1744 my $parser = DateTime::Format::ISO8601->new;
1746 # split the circs up into overdue and not-overdue circs
1748 for my $c (@$circs) {
1749 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1750 my $due = $due_dt->epoch;
1751 if ($due < DateTime->today->epoch) {
1752 push @overdue, $c->id;
1758 # grab all of the lost, claims-returned, and longoverdue circs
1759 my $open = $e->search_action_circulation(
1760 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1762 my( @lost, @cr, @lo );
1763 for my $c (@$open) {
1764 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1765 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1766 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1772 total => @$circs + @lost + @cr + @lo,
1773 out => scalar(@out),
1774 overdue => scalar(@overdue),
1775 lost => scalar(@lost),
1776 claims_returned => scalar(@cr),
1777 long_overdue => scalar(@lo)
1783 overdue => \@overdue,
1785 claims_returned => \@cr,
1786 long_overdue => \@lo
1794 __PACKAGE__->register_method(
1795 method => "user_transaction_history",
1796 api_name => "open-ils.actor.user.transactions.history",
1798 notes => <<" NOTES");
1799 Returns a list of billable transaction ids for a user, optionally by type
1801 __PACKAGE__->register_method(
1802 method => "user_transaction_history",
1803 api_name => "open-ils.actor.user.transactions.history.have_charge",
1805 notes => <<" NOTES");
1806 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1808 __PACKAGE__->register_method(
1809 method => "user_transaction_history",
1810 api_name => "open-ils.actor.user.transactions.history.have_balance",
1812 notes => <<" NOTES");
1813 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1817 sub _user_transaction_history {
1818 my( $self, $client, $login_session, $user_id, $type ) = @_;
1820 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1821 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1822 return $evt if $evt;
1824 my $api = $self->api_name();
1829 @xact = (xact_type => $type) if(defined($type));
1830 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1831 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1833 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1835 my $trans = $apputils->simple_scalar_request(
1837 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
1838 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
1840 return [ map { $_->id } @$trans ];
1845 sub user_transaction_history {
1846 my( $self, $conn, $auth, $userid, $type ) = @_;
1847 my $e = new_editor(authtoken=>$auth);
1848 return $e->event unless $e->checkauth;
1849 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1851 my $api = $self->api_name;
1852 my @xact = (xact_type => $type) if(defined($type));
1853 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1854 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1856 return $e->search_money_billable_transaction_summary(
1858 { usr => $userid, @xact, @charge, @balance },
1859 { order_by => 'xact_start DESC' }
1865 __PACKAGE__->register_method(
1866 method => "user_perms",
1867 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1869 notes => <<" NOTES");
1870 Returns a list of permissions
1873 my( $self, $client, $authtoken, $user ) = @_;
1875 my( $staff, $evt ) = $apputils->checkses($authtoken);
1876 return $evt if $evt;
1878 $user ||= $staff->id;
1880 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1884 return $apputils->simple_scalar_request(
1886 "open-ils.storage.permission.user_perms.atomic",
1890 __PACKAGE__->register_method(
1891 method => "retrieve_perms",
1892 api_name => "open-ils.actor.permissions.retrieve",
1893 notes => <<" NOTES");
1894 Returns a list of permissions
1896 sub retrieve_perms {
1897 my( $self, $client ) = @_;
1898 return $apputils->simple_scalar_request(
1900 "open-ils.cstore.direct.permission.perm_list.search.atomic",
1901 { id => { '!=' => undef } }
1905 __PACKAGE__->register_method(
1906 method => "retrieve_groups",
1907 api_name => "open-ils.actor.groups.retrieve",
1908 notes => <<" NOTES");
1909 Returns a list of user groupss
1911 sub retrieve_groups {
1912 my( $self, $client ) = @_;
1913 return new_editor()->retrieve_all_permission_grp_tree();
1916 __PACKAGE__->register_method(
1917 method => "retrieve_org_address",
1918 api_name => "open-ils.actor.org_unit.address.retrieve",
1919 notes => <<' NOTES');
1920 Returns an org_unit address by ID
1921 @param An org_address ID
1923 sub retrieve_org_address {
1924 my( $self, $client, $id ) = @_;
1925 return $apputils->simple_scalar_request(
1927 "open-ils.cstore.direct.actor.org_address.retrieve",
1932 __PACKAGE__->register_method(
1933 method => "retrieve_groups_tree",
1934 api_name => "open-ils.actor.groups.tree.retrieve",
1935 notes => <<" NOTES");
1936 Returns a list of user groups
1938 sub retrieve_groups_tree {
1939 my( $self, $client ) = @_;
1940 return new_editor()->search_permission_grp_tree(
1945 flesh_fields => { pgt => ["children"] },
1946 order_by => { pgt => 'name'}
1951 # my $groups = $apputils->simple_scalar_request(
1952 # "open-ils.storage",
1953 # "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1954 # return $self->build_group_tree($groups);
1959 # turns an org list into an org tree
1961 sub build_group_tree {
1963 my( $self, $grplist) = @_;
1965 return $grplist unless (
1966 ref($grplist) and @$grplist > 1 );
1968 my @list = sort { $a->name cmp $b->name } @$grplist;
1971 for my $grp (@list) {
1973 if ($grp and !defined($grp->parent)) {
1977 my ($parent) = grep { $_->id == $grp->parent} @list;
1979 $parent->children([]) unless defined($parent->children);
1980 push( @{$parent->children}, $grp );
1988 __PACKAGE__->register_method(
1989 method => "add_user_to_groups",
1990 api_name => "open-ils.actor.user.set_groups",
1991 notes => <<" NOTES");
1992 Adds a user to one or more permission groups
1995 sub add_user_to_groups {
1996 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1998 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1999 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2000 return $evt if $evt;
2002 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2003 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2004 return $evt if $evt;
2006 $apputils->simplereq(
2008 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2010 for my $group (@$groups) {
2011 my $link = Fieldmapper::permission::usr_grp_map->new;
2013 $link->usr($userid);
2015 my $id = $apputils->simplereq(
2017 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2023 __PACKAGE__->register_method(
2024 method => "get_user_perm_groups",
2025 api_name => "open-ils.actor.user.get_groups",
2026 notes => <<" NOTES");
2027 Retrieve a user's permission groups.
2031 sub get_user_perm_groups {
2032 my( $self, $client, $authtoken, $userid ) = @_;
2034 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2035 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2036 return $evt if $evt;
2038 return $apputils->simplereq(
2040 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2045 __PACKAGE__->register_method (
2046 method => 'register_workstation',
2047 api_name => 'open-ils.actor.workstation.register.override',
2048 signature => q/@see open-ils.actor.workstation.register/);
2050 __PACKAGE__->register_method (
2051 method => 'register_workstation',
2052 api_name => 'open-ils.actor.workstation.register',
2054 Registers a new workstion in the system
2055 @param authtoken The login session key
2056 @param name The name of the workstation id
2057 @param owner The org unit that owns this workstation
2058 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2059 if the name is already in use.
2062 sub _register_workstation {
2063 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2064 my( $requestor, $evt ) = $U->checkses($authtoken);
2065 return $evt if $evt;
2066 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2067 return $evt if $evt;
2069 my $ws = $U->cstorereq(
2070 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2071 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2073 $ws = Fieldmapper::actor::workstation->new;
2074 $ws->owning_lib($owner);
2077 my $id = $U->storagereq(
2078 'open-ils.storage.direct.actor.workstation.create', $ws );
2079 return $U->DB_UPDATE_FAILED($ws) unless $id;
2085 sub register_workstation {
2086 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2088 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2089 return $e->event unless $e->checkauth;
2090 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2091 my $existing = $e->search_actor_workstation({name => $name});
2094 if( $self->api_name =~ /override/o ) {
2095 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2096 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2098 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2102 my $ws = Fieldmapper::actor::workstation->new;
2103 $ws->owning_lib($owner);
2105 $e->create_actor_workstation($ws) or return $e->event;
2107 return $ws->id; # note: editor sets the id on the new object for us
2111 __PACKAGE__->register_method (
2112 method => 'fetch_patron_note',
2113 api_name => 'open-ils.actor.note.retrieve.all',
2115 Returns a list of notes for a given user
2116 Requestor must have VIEW_USER permission if pub==false and
2117 @param authtoken The login session key
2118 @param args Hash of params including
2119 patronid : the patron's id
2120 pub : true if retrieving only public notes
2124 sub fetch_patron_note {
2125 my( $self, $conn, $authtoken, $args ) = @_;
2126 my $patronid = $$args{patronid};
2128 my($reqr, $evt) = $U->checkses($authtoken);
2131 ($patron, $evt) = $U->fetch_user($patronid);
2132 return $evt if $evt;
2135 if( $patronid ne $reqr->id ) {
2136 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2137 return $evt if $evt;
2139 return $U->cstorereq(
2140 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2141 { usr => $patronid, pub => 't' } );
2144 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2145 return $evt if $evt;
2147 return $U->cstorereq(
2148 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2151 __PACKAGE__->register_method (
2152 method => 'create_user_note',
2153 api_name => 'open-ils.actor.note.create',
2155 Creates a new note for the given user
2156 @param authtoken The login session key
2157 @param note The note object
2160 sub create_user_note {
2161 my( $self, $conn, $authtoken, $note ) = @_;
2162 my( $reqr, $patron, $evt ) =
2163 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2164 return $evt if $evt;
2165 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2167 $note->pub('f') unless $note->pub;
2168 $note->creator($reqr->id);
2169 my $id = $U->storagereq(
2170 'open-ils.storage.direct.actor.usr_note.create', $note );
2171 return $U->DB_UPDATE_FAILED($note) unless $id;
2176 __PACKAGE__->register_method (
2177 method => 'delete_user_note',
2178 api_name => 'open-ils.actor.note.delete',
2180 Deletes a note for the given user
2181 @param authtoken The login session key
2182 @param noteid The note id
2185 sub delete_user_note {
2186 my( $self, $conn, $authtoken, $noteid ) = @_;
2188 my $note = $U->cstorereq(
2189 'open-ils.cstore.direct.actor.usr_note.retrieve', $noteid);
2190 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2192 my( $reqr, $patron, $evt ) =
2193 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2194 return $evt if $evt;
2195 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2197 my $stat = $U->storagereq(
2198 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2199 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2205 __PACKAGE__->register_method (
2206 method => 'create_closed_date',
2207 api_name => 'open-ils.actor.org_unit.closed_date.create',
2209 Creates a new closing entry for the given org_unit
2210 @param authtoken The login session key
2211 @param note The closed_date object
2214 sub create_closed_date {
2215 my( $self, $conn, $authtoken, $cd ) = @_;
2217 my( $user, $evt ) = $U->checkses($authtoken);
2218 return $evt if $evt;
2220 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2221 return $evt if $evt;
2223 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2225 my $id = $U->storagereq(
2226 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2227 return $U->DB_UPDATE_FAILED($cd) unless $id;
2232 __PACKAGE__->register_method (
2233 method => 'delete_closed_date',
2234 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2236 Deletes a closing entry for the given org_unit
2237 @param authtoken The login session key
2238 @param noteid The close_date id
2241 sub delete_closed_date {
2242 my( $self, $conn, $authtoken, $cd ) = @_;
2244 my( $user, $evt ) = $U->checkses($authtoken);
2245 return $evt if $evt;
2248 ($cd_obj, $evt) = fetch_closed_date($cd);
2249 return $evt if $evt;
2251 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2252 return $evt if $evt;
2254 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2256 my $stat = $U->storagereq(
2257 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2258 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2263 __PACKAGE__->register_method(
2264 method => 'usrname_exists',
2265 api_name => 'open-ils.actor.username.exists',
2267 Returns 1 if the requested username exists, returns 0 otherwise
2271 sub usrname_exists {
2272 my( $self, $conn, $auth, $usrname ) = @_;
2273 my $e = new_editor(authtoken=>$auth);
2274 return $e->event unless $e->checkauth;
2275 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2276 return $$a[0] if $a and @$a;
2280 __PACKAGE__->register_method(
2281 method => 'barcode_exists',
2282 api_name => 'open-ils.actor.barcode.exists',
2284 Returns 1 if the requested barcode exists, returns 0 otherwise
2288 sub barcode_exists {
2289 my( $self, $conn, $auth, $barcode ) = @_;
2290 my $e = new_editor(authtoken=>$auth);
2291 return $e->event unless $e->checkauth;
2292 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2293 return $$a[0] if $a and @$a;
2298 __PACKAGE__->register_method(
2299 method => 'retrieve_net_levels',
2300 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2303 sub retrieve_net_levels {
2304 my( $self, $conn, $auth ) = @_;
2305 my $e = new_editor(authtoken=>$auth);
2306 return $e->event unless $e->checkauth;
2307 return $e->retrieve_all_config_net_access_level();