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 }
849 if(!$card || !$card->[0]) {
850 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
854 my $user = flesh_user($card->usr());
856 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
859 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
866 __PACKAGE__->register_method(
867 method => "get_user_by_id",
868 api_name => "open-ils.actor.user.retrieve",);
871 my ($self, $client, $auth, $id) = @_;
872 my $e = new_editor(authtoken=>$auth);
873 return $e->event unless $e->checkauth;
874 my $user = $e->retrieve_actor_user($id)
876 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
882 __PACKAGE__->register_method(
883 method => "get_org_types",
884 api_name => "open-ils.actor.org_types.retrieve",);
888 my($self, $client) = @_;
889 return $org_types if $org_types;
890 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
895 __PACKAGE__->register_method(
896 method => "get_user_profiles",
897 api_name => "open-ils.actor.user.profiles.retrieve",
901 sub get_user_profiles {
902 return $user_profiles if $user_profiles;
904 return $user_profiles =
905 $apputils->simple_scalar_request(
907 "open-ils.cstore.direct.actor.profile.search.atomic", { id => { "!=" => undef }});
912 __PACKAGE__->register_method(
913 method => "get_user_ident_types",
914 api_name => "open-ils.actor.user.ident_types.retrieve",
917 sub get_user_ident_types {
918 return $ident_types if $ident_types;
919 return $ident_types =
920 new_editor()->retrieve_all_config_identification_type();
926 __PACKAGE__->register_method(
927 method => "get_org_unit",
928 api_name => "open-ils.actor.org_unit.retrieve",
932 my( $self, $client, $user_session, $org_id ) = @_;
933 my $e = new_editor(authtoken => $user_session);
935 return $e->event unless $e->checkauth;
936 $org_id = $e->requestor->ws_ou;
938 my $o = $e->retrieve_actor_org_unit($org_id)
943 __PACKAGE__->register_method(
944 method => "search_org_unit",
945 api_name => "open-ils.actor.org_unit_list.search",
948 sub search_org_unit {
950 my( $self, $client, $field, $value ) = @_;
952 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
954 "open-ils.cstore.direct.actor.org_unit.search.atomic",
955 { $field => $value } );
963 __PACKAGE__->register_method(
964 method => "get_org_tree",
965 api_name => "open-ils.actor.org_tree.retrieve",
967 note => "Returns the entire org tree structure",
971 my( $self, $client) = @_;
973 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
974 my $tree = $cache->get_cache('orgtree');
975 return $tree if $tree;
977 $tree = new_editor()->search_actor_org_unit(
979 {"parent_ou" => undef },
982 flesh_fields => { aou => ['children'] },
983 order_by => { aou => 'name'}
988 $cache->put_cache('orgtree', $tree);
993 # turns an org list into an org tree
996 my( $self, $orglist) = @_;
998 return $orglist unless (
999 ref($orglist) and @$orglist > 1 );
1002 $a->ou_type <=> $b->ou_type ||
1003 $a->name cmp $b->name } @$orglist;
1005 for my $org (@list) {
1007 next unless ($org and defined($org->parent_ou));
1008 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1009 next unless $parent;
1011 $parent->children([]) unless defined($parent->children);
1012 push( @{$parent->children}, $org );
1020 __PACKAGE__->register_method(
1021 method => "get_org_descendants",
1022 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1025 # depth is optional. org_unit is the id
1026 sub get_org_descendants {
1027 my( $self, $client, $org_unit, $depth ) = @_;
1028 my $orglist = $apputils->simple_scalar_request(
1030 "open-ils.storage.actor.org_unit.descendants.atomic",
1031 $org_unit, $depth );
1032 return $self->build_org_tree($orglist);
1036 __PACKAGE__->register_method(
1037 method => "get_org_ancestors",
1038 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1041 # depth is optional. org_unit is the id
1042 sub get_org_ancestors {
1043 my( $self, $client, $org_unit, $depth ) = @_;
1044 my $orglist = $apputils->simple_scalar_request(
1046 "open-ils.storage.actor.org_unit.ancestors.atomic",
1047 $org_unit, $depth );
1048 return $self->build_org_tree($orglist);
1052 __PACKAGE__->register_method(
1053 method => "get_standings",
1054 api_name => "open-ils.actor.standings.retrieve"
1059 return $user_standings if $user_standings;
1060 return $user_standings =
1061 $apputils->simple_scalar_request(
1063 "open-ils.cstore.direct.config.standing.search.atomic",
1064 { id => { "!=" => undef } }
1070 __PACKAGE__->register_method(
1071 method => "get_my_org_path",
1072 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1075 sub get_my_org_path {
1076 my( $self, $client, $user_session, $org_id ) = @_;
1077 my $user_obj = $apputils->check_user_session($user_session);
1078 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1080 return $apputils->simple_scalar_request(
1082 "open-ils.storage.actor.org_unit.full_path.atomic",
1087 __PACKAGE__->register_method(
1088 method => "patron_adv_search",
1089 api_name => "open-ils.actor.patron.search.advanced" );
1090 sub patron_adv_search {
1091 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1092 my $e = new_editor(authtoken=>$auth);
1093 return $e->event unless $e->checkauth;
1094 return $e->event unless $e->allowed('VIEW_USER');
1095 return $U->storagereq(
1096 "open-ils.storage.actor.user.crazy_search",
1097 $search_hash, $search_limit, $search_sort);
1102 sub _verify_password {
1103 my($user_session, $password) = @_;
1104 my $user_obj = $apputils->check_user_session($user_session);
1106 #grab the user with password
1107 $user_obj = $apputils->simple_scalar_request(
1109 "open-ils.cstore.direct.actor.user.retrieve",
1112 if($user_obj->passwd eq $password) {
1120 __PACKAGE__->register_method(
1121 method => "update_password",
1122 api_name => "open-ils.actor.user.password.update");
1124 __PACKAGE__->register_method(
1125 method => "update_password",
1126 api_name => "open-ils.actor.user.username.update");
1128 __PACKAGE__->register_method(
1129 method => "update_password",
1130 api_name => "open-ils.actor.user.email.update");
1132 sub update_password {
1133 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1137 my $user_obj = $apputils->check_user_session($user_session);
1139 if($self->api_name =~ /password/o) {
1141 #make sure they know the current password
1142 if(!_verify_password($user_session, md5_hex($current_password))) {
1143 return OpenILS::Event->new('INCORRECT_PASSWORD');
1146 $logger->debug("update_password setting new password $new_value");
1147 $user_obj->passwd($new_value);
1149 } elsif($self->api_name =~ /username/o) {
1150 my $users = search_username(undef, undef, $new_value);
1151 if( $users and $users->[0] ) {
1152 return OpenILS::Event->new('USERNAME_EXISTS');
1154 $user_obj->usrname($new_value);
1156 } elsif($self->api_name =~ /email/o) {
1157 #warn "Updating email to $new_value\n";
1158 $user_obj->email($new_value);
1161 my $session = $apputils->start_db_session();
1163 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1164 return $evt if $evt;
1166 $apputils->commit_db_session($session);
1168 if($user_obj) { return 1; }
1173 __PACKAGE__->register_method(
1174 method => "check_user_perms",
1175 api_name => "open-ils.actor.user.perm.check",
1176 notes => <<" NOTES");
1177 Takes a login session, user id, an org id, and an array of perm type strings. For each
1178 perm type, if the user does *not* have the given permission it is added
1179 to a list which is returned from the method. If all permissions
1180 are allowed, an empty list is returned
1181 if the logged in user does not match 'user_id', then the logged in user must
1182 have VIEW_PERMISSION priveleges.
1185 sub check_user_perms {
1186 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1188 my( $staff, $evt ) = $apputils->checkses($login_session);
1189 return $evt if $evt;
1191 if($staff->id ne $user_id) {
1192 if( $evt = $apputils->check_perms(
1193 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1199 for my $perm (@$perm_types) {
1200 if($apputils->check_perms($user_id, $org_id, $perm)) {
1201 push @not_allowed, $perm;
1205 return \@not_allowed
1208 __PACKAGE__->register_method(
1209 method => "check_user_perms2",
1210 api_name => "open-ils.actor.user.perm.check.multi_org",
1212 Checks the permissions on a list of perms and orgs for a user
1213 @param authtoken The login session key
1214 @param user_id The id of the user to check
1215 @param orgs The array of org ids
1216 @param perms The array of permission names
1217 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1218 if the logged in user does not match 'user_id', then the logged in user must
1219 have VIEW_PERMISSION priveleges.
1222 sub check_user_perms2 {
1223 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1225 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1226 $authtoken, $user_id, 'VIEW_PERMISSION' );
1227 return $evt if $evt;
1230 for my $org (@$orgs) {
1231 for my $perm (@$perms) {
1232 if($apputils->check_perms($user_id, $org, $perm)) {
1233 push @not_allowed, [ $org, $perm ];
1238 return \@not_allowed
1242 __PACKAGE__->register_method(
1243 method => 'check_user_perms3',
1244 api_name => 'open-ils.actor.user.perm.highest_org',
1246 Returns the highest org unit id at which a user has a given permission
1247 If the requestor does not match the target user, the requestor must have
1248 'VIEW_PERMISSION' rights at the home org unit of the target user
1249 @param authtoken The login session key
1250 @param userid The id of the user in question
1251 @param perm The permission to check
1252 @return The org unit highest in the org tree within which the user has
1253 the requested permission
1256 sub check_user_perms3 {
1257 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1259 my( $staff, $target, $org, $evt );
1261 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1262 $authtoken, $userid, 'VIEW_PERMISSION' );
1263 return $evt if $evt;
1265 my $tree = $self->get_org_tree();
1266 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1270 sub _find_highest_perm_org {
1271 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1272 my $org = $apputils->find_org($org_tree, $start_org );
1276 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1278 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1284 __PACKAGE__->register_method(
1285 method => 'check_user_perms4',
1286 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1288 Returns the highest org unit id at which a user has a given permission
1289 If the requestor does not match the target user, the requestor must have
1290 'VIEW_PERMISSION' rights at the home org unit of the target user
1291 @param authtoken The login session key
1292 @param userid The id of the user in question
1293 @param perms An array of perm names to check
1294 @return An array of orgId's representing the org unit
1295 highest in the org tree within which the user has the requested permission
1296 The arrah of orgId's has matches the order of the perms array
1299 sub check_user_perms4 {
1300 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1302 my( $staff, $target, $org, $evt );
1304 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1305 $authtoken, $userid, 'VIEW_PERMISSION' );
1306 return $evt if $evt;
1309 return [] unless ref($perms);
1310 my $tree = $self->get_org_tree();
1312 for my $p (@$perms) {
1313 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1321 __PACKAGE__->register_method(
1322 method => "user_fines_summary",
1323 api_name => "open-ils.actor.user.fines.summary",
1324 notes => <<" NOTES");
1325 Returns a short summary of the users total open fines, excluding voided fines
1326 Params are login_session, user_id
1327 Returns a 'mous' object.
1330 sub user_fines_summary {
1331 my( $self, $client, $login_session, $user_id ) = @_;
1333 my $user_obj = $apputils->check_user_session($login_session);
1334 if($user_obj->id ne $user_id) {
1335 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1336 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1340 return $apputils->simple_scalar_request(
1342 "open-ils.cstore.direct.money.open_user_summary.search",
1343 { usr => $user_id } );
1350 __PACKAGE__->register_method(
1351 method => "user_transactions",
1352 api_name => "open-ils.actor.user.transactions",
1353 notes => <<" NOTES");
1354 Returns a list of open user transactions (mbts objects);
1355 Params are login_session, user_id
1356 Optional third parameter is the transactions type. defaults to all
1359 __PACKAGE__->register_method(
1360 method => "user_transactions",
1361 api_name => "open-ils.actor.user.transactions.have_charge",
1362 notes => <<" NOTES");
1363 Returns a list of all open user transactions (mbts objects) that have an initial charge
1364 Params are login_session, user_id
1365 Optional third parameter is the transactions type. defaults to all
1368 __PACKAGE__->register_method(
1369 method => "user_transactions",
1370 api_name => "open-ils.actor.user.transactions.have_balance",
1371 notes => <<" NOTES");
1372 Returns a list of all open user transactions (mbts objects) that have a balance
1373 Params are login_session, user_id
1374 Optional third parameter is the transactions type. defaults to all
1377 __PACKAGE__->register_method(
1378 method => "user_transactions",
1379 api_name => "open-ils.actor.user.transactions.fleshed",
1380 notes => <<" NOTES");
1381 Returns an object/hash of transaction, circ, title where transaction = an open
1382 user transactions (mbts objects), circ is the attached circluation, and title
1383 is the title the circ points to
1384 Params are login_session, user_id
1385 Optional third parameter is the transactions type. defaults to all
1388 __PACKAGE__->register_method(
1389 method => "user_transactions",
1390 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1391 notes => <<" NOTES");
1392 Returns an object/hash of transaction, circ, title where transaction = an open
1393 user transactions that has an initial charge (mbts objects), circ is the
1394 attached circluation, and title is the title the circ points to
1395 Params are login_session, user_id
1396 Optional third parameter is the transactions type. defaults to all
1399 __PACKAGE__->register_method(
1400 method => "user_transactions",
1401 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1402 notes => <<" NOTES");
1403 Returns an object/hash of transaction, circ, title where transaction = an open
1404 user transaction that has a balance (mbts objects), circ is the attached
1405 circluation, and title is the title the circ points to
1406 Params are login_session, user_id
1407 Optional third parameter is the transaction type. defaults to all
1410 __PACKAGE__->register_method(
1411 method => "user_transactions",
1412 api_name => "open-ils.actor.user.transactions.count",
1413 notes => <<" NOTES");
1414 Returns an object/hash of transaction, circ, title where transaction = an open
1415 user transactions (mbts objects), circ is the attached circluation, and title
1416 is the title the circ points to
1417 Params are login_session, user_id
1418 Optional third parameter is the transactions type. defaults to all
1421 __PACKAGE__->register_method(
1422 method => "user_transactions",
1423 api_name => "open-ils.actor.user.transactions.have_charge.count",
1424 notes => <<" NOTES");
1425 Returns an object/hash of transaction, circ, title where transaction = an open
1426 user transactions that has an initial charge (mbts objects), circ is the
1427 attached circluation, and title is the title the circ points to
1428 Params are login_session, user_id
1429 Optional third parameter is the transactions type. defaults to all
1432 __PACKAGE__->register_method(
1433 method => "user_transactions",
1434 api_name => "open-ils.actor.user.transactions.have_balance.count",
1435 notes => <<" NOTES");
1436 Returns an object/hash of transaction, circ, title where transaction = an open
1437 user transaction that has a balance (mbts objects), circ is the attached
1438 circluation, and title is the title the circ points to
1439 Params are login_session, user_id
1440 Optional third parameter is the transaction type. defaults to all
1443 __PACKAGE__->register_method(
1444 method => "user_transactions",
1445 api_name => "open-ils.actor.user.transactions.have_balance.total",
1446 notes => <<" NOTES");
1447 Returns an object/hash of transaction, circ, title where transaction = an open
1448 user transaction that has a balance (mbts objects), circ is the attached
1449 circluation, and title is the title the circ points to
1450 Params are login_session, user_id
1451 Optional third parameter is the transaction type. defaults to all
1456 sub user_transactions {
1457 my( $self, $client, $login_session, $user_id, $type ) = @_;
1459 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1460 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1461 return $evt if $evt;
1463 my $api = $self->api_name();
1467 if(defined($type)) { @xact = (xact_type => $type);
1469 } else { @xact = (); }
1471 if($api =~ /have_charge/o) {
1473 $trans = $apputils->simple_scalar_request(
1475 "open-ils.cstore.direct.money.open_billable_transaction_summary.search.atomic",
1476 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1478 } elsif($api =~ /have_balance/o) {
1480 $trans = $apputils->simple_scalar_request(
1482 "open-ils.cstore.direct.money.open_billable_transaction_summary.search.atomic",
1483 { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1487 $trans = $apputils->simple_scalar_request(
1489 "open-ils.cstore.direct.money.open_billable_transaction_summary.search.atomic",
1490 { usr => $user_id, @xact });
1493 if($api =~ /total/o) {
1495 for my $t (@$trans) {
1496 $total += $t->balance_owed;
1499 $logger->debug("Total balance owed by user $user_id: $total");
1503 if($api =~ /count/o) { return scalar @$trans; }
1504 if($api !~ /fleshed/o) { return $trans; }
1507 for my $t (@$trans) {
1509 if( $t->xact_type ne 'circulation' ) {
1510 push @resp, {transaction => $t};
1514 my $circ = $apputils->simple_scalar_request(
1516 "open-ils.cstore.direct.action.circulation.retrieve",
1521 my $title = $apputils->simple_scalar_request(
1523 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1524 $circ->target_copy );
1528 my $u = OpenILS::Utils::ModsParser->new();
1529 $u->start_mods_batch($title->marc());
1530 my $mods = $u->finish_mods_batch();
1532 push @resp, {transaction => $t, circ => $circ, record => $mods };
1540 __PACKAGE__->register_method(
1541 method => "user_transaction_retrieve",
1542 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1544 notes => <<" NOTES");
1545 Returns a fleshedtransaction record
1547 __PACKAGE__->register_method(
1548 method => "user_transaction_retrieve",
1549 api_name => "open-ils.actor.user.transaction.retrieve",
1551 notes => <<" NOTES");
1552 Returns a transaction record
1554 sub user_transaction_retrieve {
1555 my( $self, $client, $login_session, $bill_id ) = @_;
1557 my $trans = $apputils->simple_scalar_request(
1559 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1563 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1564 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1565 return $evt if $evt;
1567 my $api = $self->api_name();
1568 if($api !~ /fleshed/o) { return $trans; }
1570 if( $trans->xact_type ne 'circulation' ) {
1571 $logger->debug("Returning non-circ transaction");
1572 return {transaction => $trans};
1575 my $circ = $apputils->simple_scalar_request(
1577 "open-ils..direct.action.circulation.retrieve",
1580 return {transaction => $trans} unless $circ;
1581 $logger->debug("Found the circ transaction");
1583 my $title = $apputils->simple_scalar_request(
1585 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1586 $circ->target_copy );
1588 return {transaction => $trans, circ => $circ } unless $title;
1589 $logger->debug("Found the circ title");
1593 my $u = OpenILS::Utils::ModsParser->new();
1594 $u->start_mods_batch($title->marc());
1595 $mods = $u->finish_mods_batch();
1597 if ($title->id == -1) {
1598 my $copy = $apputils->simple_scalar_request(
1600 "open-ils.cstore.direct.asset.copy.retrieve",
1601 $circ->target_copy );
1603 $mods = new Fieldmapper::metabib::virtual_record;
1605 $mods->title($copy->dummy_title);
1606 $mods->author($copy->dummy_author);
1610 $logger->debug("MODSized the circ title");
1612 return {transaction => $trans, circ => $circ, record => $mods };
1616 __PACKAGE__->register_method(
1617 method => "hold_request_count",
1618 api_name => "open-ils.actor.user.hold_requests.count",
1620 notes => <<" NOTES");
1621 Returns hold ready/total counts
1623 sub hold_request_count {
1624 my( $self, $client, $login_session, $userid ) = @_;
1626 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1627 $login_session, $userid, 'VIEW_HOLD' );
1628 return $evt if $evt;
1631 my $holds = $apputils->simple_scalar_request(
1633 "open-ils.cstore.direct.action.hold_request.search.atomic",
1635 fulfillment_time => {"=" => undef } }
1639 for my $h (@$holds) {
1640 next unless $h->capture_time and $h->current_copy;
1642 my $copy = $apputils->simple_scalar_request(
1644 "open-ils.cstore.direct.asset.copy.retrieve",
1648 if ($copy and $copy->status == 8) {
1653 return { total => scalar(@$holds), ready => scalar(@ready) };
1657 __PACKAGE__->register_method(
1658 method => "checkedout_count",
1659 api_name => "open-ils.actor.user.checked_out.count__",
1661 notes => <<" NOTES");
1662 Returns a transaction record
1666 sub checkedout_count {
1667 my( $self, $client, $login_session, $userid ) = @_;
1669 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1670 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1671 return $evt if $evt;
1673 my $circs = $apputils->simple_scalar_request(
1675 "open-ils.cstore.direct.action.circulation.search.atomic",
1676 { usr => $userid, stop_fines => undef }
1677 #{ usr => $userid, checkin_time => {"=" => undef } }
1680 my $parser = DateTime::Format::ISO8601->new;
1683 for my $c (@$circs) {
1684 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1685 my $due = $due_dt->epoch;
1687 if ($due < DateTime->today->epoch) {
1692 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1696 __PACKAGE__->register_method(
1697 method => "checked_out",
1698 api_name => "open-ils.actor.user.checked_out",
1701 Returns a structure of circulations objects sorted by
1702 out, overdue, lost, claims_returned, long_overdue.
1703 A list of IDs are returned of each type.
1704 lost, long_overdue, and claims_returned circ will not
1705 be "finished" (there is an outstanding balance or some
1706 other pending action on the circ).
1708 The .count method also includes a 'total' field which
1709 sums all "open" circs
1713 __PACKAGE__->register_method(
1714 method => "checked_out",
1715 api_name => "open-ils.actor.user.checked_out.count",
1717 signature => q/@see open-ils.actor.user.checked_out/
1721 my( $self, $conn, $auth, $userid ) = @_;
1723 my $e = new_editor(authtoken=>$auth);
1724 return $e->event unless $e->checkauth;
1726 if( $userid ne $e->requestor->id ) {
1727 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1730 my $count = $self->api_name =~ /count/;
1731 return _checked_out( $count, $e, $userid );
1735 my( $iscount, $e, $userid ) = @_;
1737 my $circs = $e->search_action_circulation(
1738 { usr => $userid, stop_fines => undef });
1740 my $parser = DateTime::Format::ISO8601->new;
1742 # split the circs up into overdue and not-overdue circs
1744 for my $c (@$circs) {
1745 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1746 my $due = $due_dt->epoch;
1747 if ($due < DateTime->today->epoch) {
1748 push @overdue, $c->id;
1754 # grab all of the lost, claims-returned, and longoverdue circs
1755 my $open = $e->search_action_circulation(
1756 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1758 my( @lost, @cr, @lo );
1759 for my $c (@$open) {
1760 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1761 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1762 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1768 total => @$circs + @lost + @cr + @lo,
1769 out => scalar(@out),
1770 overdue => scalar(@overdue),
1771 lost => scalar(@lost),
1772 claims_returned => scalar(@cr),
1773 long_overdue => scalar(@lo)
1779 overdue => \@overdue,
1781 claims_returned => \@cr,
1782 long_overdue => \@lo
1790 __PACKAGE__->register_method(
1791 method => "user_transaction_history",
1792 api_name => "open-ils.actor.user.transactions.history",
1794 notes => <<" NOTES");
1795 Returns a list of billable transaction ids for a user, optionally by type
1797 __PACKAGE__->register_method(
1798 method => "user_transaction_history",
1799 api_name => "open-ils.actor.user.transactions.history.have_charge",
1801 notes => <<" NOTES");
1802 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1804 __PACKAGE__->register_method(
1805 method => "user_transaction_history",
1806 api_name => "open-ils.actor.user.transactions.history.have_balance",
1808 notes => <<" NOTES");
1809 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1813 sub _user_transaction_history {
1814 my( $self, $client, $login_session, $user_id, $type ) = @_;
1816 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1817 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1818 return $evt if $evt;
1820 my $api = $self->api_name();
1825 @xact = (xact_type => $type) if(defined($type));
1826 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1827 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1829 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1831 my $trans = $apputils->simple_scalar_request(
1833 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
1834 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
1836 return [ map { $_->id } @$trans ];
1841 sub user_transaction_history {
1842 my( $self, $conn, $auth, $userid, $type ) = @_;
1843 my $e = new_editor(authtoken=>$auth);
1844 return $e->event unless $e->checkauth;
1845 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1847 my $api = $self->api_name;
1848 my @xact = (xact_type => $type) if(defined($type));
1849 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1850 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1852 return $e->search_money_billable_transaction_summary(
1854 { usr => $userid, @xact, @charge, @balance },
1855 { order_by => 'xact_start DESC' }
1861 __PACKAGE__->register_method(
1862 method => "user_perms",
1863 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1865 notes => <<" NOTES");
1866 Returns a list of permissions
1869 my( $self, $client, $authtoken, $user ) = @_;
1871 my( $staff, $evt ) = $apputils->checkses($authtoken);
1872 return $evt if $evt;
1874 $user ||= $staff->id;
1876 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1880 return $apputils->simple_scalar_request(
1882 "open-ils.storage.permission.user_perms.atomic",
1886 __PACKAGE__->register_method(
1887 method => "retrieve_perms",
1888 api_name => "open-ils.actor.permissions.retrieve",
1889 notes => <<" NOTES");
1890 Returns a list of permissions
1892 sub retrieve_perms {
1893 my( $self, $client ) = @_;
1894 return $apputils->simple_scalar_request(
1896 "open-ils.cstore.direct.permission.perm_list.search.atomic",
1897 { id => { '!=' => undef } }
1901 __PACKAGE__->register_method(
1902 method => "retrieve_groups",
1903 api_name => "open-ils.actor.groups.retrieve",
1904 notes => <<" NOTES");
1905 Returns a list of user groupss
1907 sub retrieve_groups {
1908 my( $self, $client ) = @_;
1909 return new_editor()->retrieve_all_permission_grp_tree();
1912 __PACKAGE__->register_method(
1913 method => "retrieve_org_address",
1914 api_name => "open-ils.actor.org_unit.address.retrieve",
1915 notes => <<' NOTES');
1916 Returns an org_unit address by ID
1917 @param An org_address ID
1919 sub retrieve_org_address {
1920 my( $self, $client, $id ) = @_;
1921 return $apputils->simple_scalar_request(
1923 "open-ils.cstore.direct.actor.org_address.retrieve",
1928 __PACKAGE__->register_method(
1929 method => "retrieve_groups_tree",
1930 api_name => "open-ils.actor.groups.tree.retrieve",
1931 notes => <<" NOTES");
1932 Returns a list of user groups
1934 sub retrieve_groups_tree {
1935 my( $self, $client ) = @_;
1936 return new_editor()->search_permission_grp_tree(
1941 flesh_fields => { pgt => ["children"] },
1942 order_by => { pgt => 'name'}
1949 # turns an org list into an org tree
1951 sub build_group_tree {
1953 my( $self, $grplist) = @_;
1955 return $grplist unless (
1956 ref($grplist) and @$grplist > 1 );
1958 my @list = sort { $a->name cmp $b->name } @$grplist;
1961 for my $grp (@list) {
1963 if ($grp and !defined($grp->parent)) {
1967 my ($parent) = grep { $_->id == $grp->parent} @list;
1969 $parent->children([]) unless defined($parent->children);
1970 push( @{$parent->children}, $grp );
1978 __PACKAGE__->register_method(
1979 method => "add_user_to_groups",
1980 api_name => "open-ils.actor.user.set_groups",
1981 notes => <<" NOTES");
1982 Adds a user to one or more permission groups
1985 sub add_user_to_groups {
1986 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1988 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1989 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1990 return $evt if $evt;
1992 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1993 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1994 return $evt if $evt;
1996 $apputils->simplereq(
1998 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2000 for my $group (@$groups) {
2001 my $link = Fieldmapper::permission::usr_grp_map->new;
2003 $link->usr($userid);
2005 my $id = $apputils->simplereq(
2007 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2013 __PACKAGE__->register_method(
2014 method => "get_user_perm_groups",
2015 api_name => "open-ils.actor.user.get_groups",
2016 notes => <<" NOTES");
2017 Retrieve a user's permission groups.
2021 sub get_user_perm_groups {
2022 my( $self, $client, $authtoken, $userid ) = @_;
2024 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2025 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2026 return $evt if $evt;
2028 return $apputils->simplereq(
2030 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2035 __PACKAGE__->register_method (
2036 method => 'register_workstation',
2037 api_name => 'open-ils.actor.workstation.register.override',
2038 signature => q/@see open-ils.actor.workstation.register/);
2040 __PACKAGE__->register_method (
2041 method => 'register_workstation',
2042 api_name => 'open-ils.actor.workstation.register',
2044 Registers a new workstion in the system
2045 @param authtoken The login session key
2046 @param name The name of the workstation id
2047 @param owner The org unit that owns this workstation
2048 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2049 if the name is already in use.
2052 sub _register_workstation {
2053 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2054 my( $requestor, $evt ) = $U->checkses($authtoken);
2055 return $evt if $evt;
2056 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2057 return $evt if $evt;
2059 my $ws = $U->cstorereq(
2060 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2061 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2063 $ws = Fieldmapper::actor::workstation->new;
2064 $ws->owning_lib($owner);
2067 my $id = $U->storagereq(
2068 'open-ils.storage.direct.actor.workstation.create', $ws );
2069 return $U->DB_UPDATE_FAILED($ws) unless $id;
2075 sub register_workstation {
2076 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2078 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2079 return $e->event unless $e->checkauth;
2080 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2081 my $existing = $e->search_actor_workstation({name => $name});
2084 if( $self->api_name =~ /override/o ) {
2085 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2086 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2088 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2092 my $ws = Fieldmapper::actor::workstation->new;
2093 $ws->owning_lib($owner);
2095 $e->create_actor_workstation($ws) or return $e->event;
2097 return $ws->id; # note: editor sets the id on the new object for us
2101 __PACKAGE__->register_method (
2102 method => 'fetch_patron_note',
2103 api_name => 'open-ils.actor.note.retrieve.all',
2105 Returns a list of notes for a given user
2106 Requestor must have VIEW_USER permission if pub==false and
2107 @param authtoken The login session key
2108 @param args Hash of params including
2109 patronid : the patron's id
2110 pub : true if retrieving only public notes
2114 sub fetch_patron_note {
2115 my( $self, $conn, $authtoken, $args ) = @_;
2116 my $patronid = $$args{patronid};
2118 my($reqr, $evt) = $U->checkses($authtoken);
2121 ($patron, $evt) = $U->fetch_user($patronid);
2122 return $evt if $evt;
2125 if( $patronid ne $reqr->id ) {
2126 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2127 return $evt if $evt;
2129 return $U->cstorereq(
2130 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2131 { usr => $patronid, pub => 't' } );
2134 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2135 return $evt if $evt;
2137 return $U->cstorereq(
2138 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2141 __PACKAGE__->register_method (
2142 method => 'create_user_note',
2143 api_name => 'open-ils.actor.note.create',
2145 Creates a new note for the given user
2146 @param authtoken The login session key
2147 @param note The note object
2150 sub create_user_note {
2151 my( $self, $conn, $authtoken, $note ) = @_;
2152 my( $reqr, $patron, $evt ) =
2153 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2154 return $evt if $evt;
2155 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2157 $note->pub('f') unless $note->pub;
2158 $note->creator($reqr->id);
2159 my $id = $U->storagereq(
2160 'open-ils.storage.direct.actor.usr_note.create', $note );
2161 return $U->DB_UPDATE_FAILED($note) unless $id;
2166 __PACKAGE__->register_method (
2167 method => 'delete_user_note',
2168 api_name => 'open-ils.actor.note.delete',
2170 Deletes a note for the given user
2171 @param authtoken The login session key
2172 @param noteid The note id
2175 sub delete_user_note {
2176 my( $self, $conn, $authtoken, $noteid ) = @_;
2178 my $note = $U->cstorereq(
2179 'open-ils.cstore.direct.actor.usr_note.retrieve', $noteid);
2180 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2182 my( $reqr, $patron, $evt ) =
2183 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2184 return $evt if $evt;
2185 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2187 my $stat = $U->storagereq(
2188 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2189 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2195 __PACKAGE__->register_method (
2196 method => 'create_closed_date',
2197 api_name => 'open-ils.actor.org_unit.closed_date.create',
2199 Creates a new closing entry for the given org_unit
2200 @param authtoken The login session key
2201 @param note The closed_date object
2204 sub create_closed_date {
2205 my( $self, $conn, $authtoken, $cd ) = @_;
2207 my( $user, $evt ) = $U->checkses($authtoken);
2208 return $evt if $evt;
2210 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2211 return $evt if $evt;
2213 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2215 my $id = $U->storagereq(
2216 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2217 return $U->DB_UPDATE_FAILED($cd) unless $id;
2222 __PACKAGE__->register_method (
2223 method => 'delete_closed_date',
2224 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2226 Deletes a closing entry for the given org_unit
2227 @param authtoken The login session key
2228 @param noteid The close_date id
2231 sub delete_closed_date {
2232 my( $self, $conn, $authtoken, $cd ) = @_;
2234 my( $user, $evt ) = $U->checkses($authtoken);
2235 return $evt if $evt;
2238 ($cd_obj, $evt) = fetch_closed_date($cd);
2239 return $evt if $evt;
2241 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2242 return $evt if $evt;
2244 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2246 my $stat = $U->storagereq(
2247 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2248 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2253 __PACKAGE__->register_method(
2254 method => 'usrname_exists',
2255 api_name => 'open-ils.actor.username.exists',
2257 Returns 1 if the requested username exists, returns 0 otherwise
2261 sub usrname_exists {
2262 my( $self, $conn, $auth, $usrname ) = @_;
2263 my $e = new_editor(authtoken=>$auth);
2264 return $e->event unless $e->checkauth;
2265 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2266 return $$a[0] if $a and @$a;
2270 __PACKAGE__->register_method(
2271 method => 'barcode_exists',
2272 api_name => 'open-ils.actor.barcode.exists',
2274 Returns 1 if the requested barcode exists, returns 0 otherwise
2278 sub barcode_exists {
2279 my( $self, $conn, $auth, $barcode ) = @_;
2280 my $e = new_editor(authtoken=>$auth);
2281 return $e->event unless $e->checkauth;
2282 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2283 return $$a[0] if $a and @$a;
2288 __PACKAGE__->register_method(
2289 method => 'retrieve_net_levels',
2290 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2293 sub retrieve_net_levels {
2294 my( $self, $conn, $auth ) = @_;
2295 my $e = new_editor(authtoken=>$auth);
2296 return $e->event unless $e->checkauth;
2297 return $e->retrieve_all_config_net_access_level();