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();
1531 $mods->doc_id($title->id) if $mods;
1533 push @resp, {transaction => $t, circ => $circ, record => $mods };
1541 __PACKAGE__->register_method(
1542 method => "user_transaction_retrieve",
1543 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1545 notes => <<" NOTES");
1546 Returns a fleshedtransaction record
1548 __PACKAGE__->register_method(
1549 method => "user_transaction_retrieve",
1550 api_name => "open-ils.actor.user.transaction.retrieve",
1552 notes => <<" NOTES");
1553 Returns a transaction record
1555 sub user_transaction_retrieve {
1556 my( $self, $client, $login_session, $bill_id ) = @_;
1558 my $trans = $apputils->simple_scalar_request(
1560 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1564 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1565 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1566 return $evt if $evt;
1568 my $api = $self->api_name();
1569 if($api !~ /fleshed/o) { return $trans; }
1571 if( $trans->xact_type ne 'circulation' ) {
1572 $logger->debug("Returning non-circ transaction");
1573 return {transaction => $trans};
1576 my $circ = $apputils->simple_scalar_request(
1578 "open-ils..direct.action.circulation.retrieve",
1581 return {transaction => $trans} unless $circ;
1582 $logger->debug("Found the circ transaction");
1584 my $title = $apputils->simple_scalar_request(
1586 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1587 $circ->target_copy );
1589 return {transaction => $trans, circ => $circ } unless $title;
1590 $logger->debug("Found the circ title");
1594 my $u = OpenILS::Utils::ModsParser->new();
1595 $u->start_mods_batch($title->marc());
1596 $mods = $u->finish_mods_batch();
1598 if ($title->id == -1) {
1599 my $copy = $apputils->simple_scalar_request(
1601 "open-ils.cstore.direct.asset.copy.retrieve",
1602 $circ->target_copy );
1604 $mods = new Fieldmapper::metabib::virtual_record;
1606 $mods->title($copy->dummy_title);
1607 $mods->author($copy->dummy_author);
1611 $logger->debug("MODSized the circ title");
1613 return {transaction => $trans, circ => $circ, record => $mods };
1617 __PACKAGE__->register_method(
1618 method => "hold_request_count",
1619 api_name => "open-ils.actor.user.hold_requests.count",
1621 notes => <<" NOTES");
1622 Returns hold ready/total counts
1624 sub hold_request_count {
1625 my( $self, $client, $login_session, $userid ) = @_;
1627 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1628 $login_session, $userid, 'VIEW_HOLD' );
1629 return $evt if $evt;
1632 my $holds = $apputils->simple_scalar_request(
1634 "open-ils.cstore.direct.action.hold_request.search.atomic",
1636 fulfillment_time => {"=" => undef } }
1640 for my $h (@$holds) {
1641 next unless $h->capture_time and $h->current_copy;
1643 my $copy = $apputils->simple_scalar_request(
1645 "open-ils.cstore.direct.asset.copy.retrieve",
1649 if ($copy and $copy->status == 8) {
1654 return { total => scalar(@$holds), ready => scalar(@ready) };
1658 __PACKAGE__->register_method(
1659 method => "checkedout_count",
1660 api_name => "open-ils.actor.user.checked_out.count__",
1662 notes => <<" NOTES");
1663 Returns a transaction record
1667 sub checkedout_count {
1668 my( $self, $client, $login_session, $userid ) = @_;
1670 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1671 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1672 return $evt if $evt;
1674 my $circs = $apputils->simple_scalar_request(
1676 "open-ils.cstore.direct.action.circulation.search.atomic",
1677 { usr => $userid, stop_fines => undef }
1678 #{ usr => $userid, checkin_time => {"=" => undef } }
1681 my $parser = DateTime::Format::ISO8601->new;
1684 for my $c (@$circs) {
1685 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1686 my $due = $due_dt->epoch;
1688 if ($due < DateTime->today->epoch) {
1693 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1697 __PACKAGE__->register_method(
1698 method => "checked_out",
1699 api_name => "open-ils.actor.user.checked_out",
1702 Returns a structure of circulations objects sorted by
1703 out, overdue, lost, claims_returned, long_overdue.
1704 A list of IDs are returned of each type.
1705 lost, long_overdue, and claims_returned circ will not
1706 be "finished" (there is an outstanding balance or some
1707 other pending action on the circ).
1709 The .count method also includes a 'total' field which
1710 sums all "open" circs
1714 __PACKAGE__->register_method(
1715 method => "checked_out",
1716 api_name => "open-ils.actor.user.checked_out.count",
1718 signature => q/@see open-ils.actor.user.checked_out/
1722 my( $self, $conn, $auth, $userid ) = @_;
1724 my $e = new_editor(authtoken=>$auth);
1725 return $e->event unless $e->checkauth;
1727 if( $userid ne $e->requestor->id ) {
1728 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1731 my $count = $self->api_name =~ /count/;
1732 return _checked_out( $count, $e, $userid );
1736 my( $iscount, $e, $userid ) = @_;
1738 my $circs = $e->search_action_circulation(
1739 { usr => $userid, stop_fines => undef });
1741 my $parser = DateTime::Format::ISO8601->new;
1743 # split the circs up into overdue and not-overdue circs
1745 for my $c (@$circs) {
1746 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1747 my $due = $due_dt->epoch;
1748 if ($due < DateTime->today->epoch) {
1749 push @overdue, $c->id;
1755 # grab all of the lost, claims-returned, and longoverdue circs
1756 my $open = $e->search_action_circulation(
1757 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1759 my( @lost, @cr, @lo );
1760 for my $c (@$open) {
1761 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1762 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1763 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1769 total => @$circs + @lost + @cr + @lo,
1770 out => scalar(@out),
1771 overdue => scalar(@overdue),
1772 lost => scalar(@lost),
1773 claims_returned => scalar(@cr),
1774 long_overdue => scalar(@lo)
1780 overdue => \@overdue,
1782 claims_returned => \@cr,
1783 long_overdue => \@lo
1791 __PACKAGE__->register_method(
1792 method => "user_transaction_history",
1793 api_name => "open-ils.actor.user.transactions.history",
1795 notes => <<" NOTES");
1796 Returns a list of billable transaction ids for a user, optionally by type
1798 __PACKAGE__->register_method(
1799 method => "user_transaction_history",
1800 api_name => "open-ils.actor.user.transactions.history.have_charge",
1802 notes => <<" NOTES");
1803 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1805 __PACKAGE__->register_method(
1806 method => "user_transaction_history",
1807 api_name => "open-ils.actor.user.transactions.history.have_balance",
1809 notes => <<" NOTES");
1810 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1814 sub _user_transaction_history {
1815 my( $self, $client, $login_session, $user_id, $type ) = @_;
1817 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1818 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1819 return $evt if $evt;
1821 my $api = $self->api_name();
1826 @xact = (xact_type => $type) if(defined($type));
1827 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1828 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1830 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1832 my $trans = $apputils->simple_scalar_request(
1834 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
1835 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
1837 return [ map { $_->id } @$trans ];
1842 sub user_transaction_history {
1843 my( $self, $conn, $auth, $userid, $type ) = @_;
1844 my $e = new_editor(authtoken=>$auth);
1845 return $e->event unless $e->checkauth;
1846 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1848 my $api = $self->api_name;
1849 my @xact = (xact_type => $type) if(defined($type));
1850 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1851 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1853 return $e->search_money_billable_transaction_summary(
1855 { usr => $userid, @xact, @charge, @balance },
1856 { order_by => 'xact_start DESC' }
1862 __PACKAGE__->register_method(
1863 method => "user_perms",
1864 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1866 notes => <<" NOTES");
1867 Returns a list of permissions
1870 my( $self, $client, $authtoken, $user ) = @_;
1872 my( $staff, $evt ) = $apputils->checkses($authtoken);
1873 return $evt if $evt;
1875 $user ||= $staff->id;
1877 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1881 return $apputils->simple_scalar_request(
1883 "open-ils.storage.permission.user_perms.atomic",
1887 __PACKAGE__->register_method(
1888 method => "retrieve_perms",
1889 api_name => "open-ils.actor.permissions.retrieve",
1890 notes => <<" NOTES");
1891 Returns a list of permissions
1893 sub retrieve_perms {
1894 my( $self, $client ) = @_;
1895 return $apputils->simple_scalar_request(
1897 "open-ils.cstore.direct.permission.perm_list.search.atomic",
1898 { id => { '!=' => undef } }
1902 __PACKAGE__->register_method(
1903 method => "retrieve_groups",
1904 api_name => "open-ils.actor.groups.retrieve",
1905 notes => <<" NOTES");
1906 Returns a list of user groupss
1908 sub retrieve_groups {
1909 my( $self, $client ) = @_;
1910 return new_editor()->retrieve_all_permission_grp_tree();
1913 __PACKAGE__->register_method(
1914 method => "retrieve_org_address",
1915 api_name => "open-ils.actor.org_unit.address.retrieve",
1916 notes => <<' NOTES');
1917 Returns an org_unit address by ID
1918 @param An org_address ID
1920 sub retrieve_org_address {
1921 my( $self, $client, $id ) = @_;
1922 return $apputils->simple_scalar_request(
1924 "open-ils.cstore.direct.actor.org_address.retrieve",
1929 __PACKAGE__->register_method(
1930 method => "retrieve_groups_tree",
1931 api_name => "open-ils.actor.groups.tree.retrieve",
1932 notes => <<" NOTES");
1933 Returns a list of user groups
1935 sub retrieve_groups_tree {
1936 my( $self, $client ) = @_;
1937 return new_editor()->search_permission_grp_tree(
1942 flesh_fields => { pgt => ["children"] },
1943 order_by => { pgt => 'name'}
1950 # turns an org list into an org tree
1952 sub build_group_tree {
1954 my( $self, $grplist) = @_;
1956 return $grplist unless (
1957 ref($grplist) and @$grplist > 1 );
1959 my @list = sort { $a->name cmp $b->name } @$grplist;
1962 for my $grp (@list) {
1964 if ($grp and !defined($grp->parent)) {
1968 my ($parent) = grep { $_->id == $grp->parent} @list;
1970 $parent->children([]) unless defined($parent->children);
1971 push( @{$parent->children}, $grp );
1979 __PACKAGE__->register_method(
1980 method => "add_user_to_groups",
1981 api_name => "open-ils.actor.user.set_groups",
1982 notes => <<" NOTES");
1983 Adds a user to one or more permission groups
1986 sub add_user_to_groups {
1987 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1989 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1990 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1991 return $evt if $evt;
1993 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1994 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1995 return $evt if $evt;
1997 $apputils->simplereq(
1999 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2001 for my $group (@$groups) {
2002 my $link = Fieldmapper::permission::usr_grp_map->new;
2004 $link->usr($userid);
2006 my $id = $apputils->simplereq(
2008 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2014 __PACKAGE__->register_method(
2015 method => "get_user_perm_groups",
2016 api_name => "open-ils.actor.user.get_groups",
2017 notes => <<" NOTES");
2018 Retrieve a user's permission groups.
2022 sub get_user_perm_groups {
2023 my( $self, $client, $authtoken, $userid ) = @_;
2025 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2026 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2027 return $evt if $evt;
2029 return $apputils->simplereq(
2031 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2036 __PACKAGE__->register_method (
2037 method => 'register_workstation',
2038 api_name => 'open-ils.actor.workstation.register.override',
2039 signature => q/@see open-ils.actor.workstation.register/);
2041 __PACKAGE__->register_method (
2042 method => 'register_workstation',
2043 api_name => 'open-ils.actor.workstation.register',
2045 Registers a new workstion in the system
2046 @param authtoken The login session key
2047 @param name The name of the workstation id
2048 @param owner The org unit that owns this workstation
2049 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2050 if the name is already in use.
2053 sub _register_workstation {
2054 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2055 my( $requestor, $evt ) = $U->checkses($authtoken);
2056 return $evt if $evt;
2057 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2058 return $evt if $evt;
2060 my $ws = $U->cstorereq(
2061 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2062 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2064 $ws = Fieldmapper::actor::workstation->new;
2065 $ws->owning_lib($owner);
2068 my $id = $U->storagereq(
2069 'open-ils.storage.direct.actor.workstation.create', $ws );
2070 return $U->DB_UPDATE_FAILED($ws) unless $id;
2076 sub register_workstation {
2077 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2079 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2080 return $e->event unless $e->checkauth;
2081 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2082 my $existing = $e->search_actor_workstation({name => $name});
2085 if( $self->api_name =~ /override/o ) {
2086 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2087 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2089 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2093 my $ws = Fieldmapper::actor::workstation->new;
2094 $ws->owning_lib($owner);
2096 $e->create_actor_workstation($ws) or return $e->event;
2098 return $ws->id; # note: editor sets the id on the new object for us
2102 __PACKAGE__->register_method (
2103 method => 'fetch_patron_note',
2104 api_name => 'open-ils.actor.note.retrieve.all',
2106 Returns a list of notes for a given user
2107 Requestor must have VIEW_USER permission if pub==false and
2108 @param authtoken The login session key
2109 @param args Hash of params including
2110 patronid : the patron's id
2111 pub : true if retrieving only public notes
2115 sub fetch_patron_note {
2116 my( $self, $conn, $authtoken, $args ) = @_;
2117 my $patronid = $$args{patronid};
2119 my($reqr, $evt) = $U->checkses($authtoken);
2122 ($patron, $evt) = $U->fetch_user($patronid);
2123 return $evt if $evt;
2126 if( $patronid ne $reqr->id ) {
2127 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2128 return $evt if $evt;
2130 return $U->cstorereq(
2131 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2132 { usr => $patronid, pub => 't' } );
2135 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2136 return $evt if $evt;
2138 return $U->cstorereq(
2139 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2142 __PACKAGE__->register_method (
2143 method => 'create_user_note',
2144 api_name => 'open-ils.actor.note.create',
2146 Creates a new note for the given user
2147 @param authtoken The login session key
2148 @param note The note object
2151 sub create_user_note {
2152 my( $self, $conn, $authtoken, $note ) = @_;
2153 my( $reqr, $patron, $evt ) =
2154 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2155 return $evt if $evt;
2156 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2158 $note->pub('f') unless $note->pub;
2159 $note->creator($reqr->id);
2160 my $id = $U->storagereq(
2161 'open-ils.storage.direct.actor.usr_note.create', $note );
2162 return $U->DB_UPDATE_FAILED($note) unless $id;
2167 __PACKAGE__->register_method (
2168 method => 'delete_user_note',
2169 api_name => 'open-ils.actor.note.delete',
2171 Deletes a note for the given user
2172 @param authtoken The login session key
2173 @param noteid The note id
2176 sub delete_user_note {
2177 my( $self, $conn, $authtoken, $noteid ) = @_;
2179 my $note = $U->cstorereq(
2180 'open-ils.cstore.direct.actor.usr_note.retrieve', $noteid);
2181 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2183 my( $reqr, $patron, $evt ) =
2184 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2185 return $evt if $evt;
2186 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2188 my $stat = $U->storagereq(
2189 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2190 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2195 __PACKAGE__->register_method (
2196 method => 'update_user_note',
2197 api_name => 'open-ils.actor.note.update',
2199 @param authtoken The login session key
2200 @param note The note
2204 sub update_user_note {
2205 my( $self, $conn, $auth, $note ) = @_;
2206 my $e = new_editor(authtoken=>$auth, xact=>1);
2207 return $e->event unless $e->checkauth;
2208 my $patron = $e->retrieve_actor_user($note->usr)
2209 or return $e->event;
2210 return $e->event unless
2211 $e->allowed('UPDATE_USER', $patron->home_ou);
2212 $e->update_actor_user_note($note)
2213 or return $e->event;
2221 __PACKAGE__->register_method (
2222 method => 'create_closed_date',
2223 api_name => 'open-ils.actor.org_unit.closed_date.create',
2225 Creates a new closing entry for the given org_unit
2226 @param authtoken The login session key
2227 @param note The closed_date object
2230 sub create_closed_date {
2231 my( $self, $conn, $authtoken, $cd ) = @_;
2233 my( $user, $evt ) = $U->checkses($authtoken);
2234 return $evt if $evt;
2236 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2237 return $evt if $evt;
2239 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2241 my $id = $U->storagereq(
2242 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2243 return $U->DB_UPDATE_FAILED($cd) unless $id;
2248 __PACKAGE__->register_method (
2249 method => 'delete_closed_date',
2250 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2252 Deletes a closing entry for the given org_unit
2253 @param authtoken The login session key
2254 @param noteid The close_date id
2257 sub delete_closed_date {
2258 my( $self, $conn, $authtoken, $cd ) = @_;
2260 my( $user, $evt ) = $U->checkses($authtoken);
2261 return $evt if $evt;
2264 ($cd_obj, $evt) = fetch_closed_date($cd);
2265 return $evt if $evt;
2267 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2268 return $evt if $evt;
2270 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2272 my $stat = $U->storagereq(
2273 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2274 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2279 __PACKAGE__->register_method(
2280 method => 'usrname_exists',
2281 api_name => 'open-ils.actor.username.exists',
2283 Returns 1 if the requested username exists, returns 0 otherwise
2287 sub usrname_exists {
2288 my( $self, $conn, $auth, $usrname ) = @_;
2289 my $e = new_editor(authtoken=>$auth);
2290 return $e->event unless $e->checkauth;
2291 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2292 return $$a[0] if $a and @$a;
2296 __PACKAGE__->register_method(
2297 method => 'barcode_exists',
2298 api_name => 'open-ils.actor.barcode.exists',
2300 Returns 1 if the requested barcode exists, returns 0 otherwise
2304 sub barcode_exists {
2305 my( $self, $conn, $auth, $barcode ) = @_;
2306 my $e = new_editor(authtoken=>$auth);
2307 return $e->event unless $e->checkauth;
2308 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2309 return $$a[0] if $a and @$a;
2314 __PACKAGE__->register_method(
2315 method => 'retrieve_net_levels',
2316 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2319 sub retrieve_net_levels {
2320 my( $self, $conn, $auth ) = @_;
2321 my $e = new_editor(authtoken=>$auth);
2322 return $e->event unless $e->checkauth;
2323 return $e->retrieve_all_config_net_access_level();