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;
23 use DateTime::Format::ISO8601;
25 use OpenILS::Application::Actor::Container;
26 use OpenILS::Application::Actor::ClosedDates;
28 use OpenILS::Utils::Editor qw/:funcs/;
30 use OpenILS::Application::Actor::UserGroups;
32 OpenILS::Application::Actor::Container->initialize();
33 OpenILS::Application::Actor::UserGroups->initialize();
34 OpenILS::Application::Actor::ClosedDates->initialize();
37 my $apputils = "OpenILS::Application::AppUtils";
40 sub _d { warn "Patron:\n" . Dumper(shift()); }
45 my $set_user_settings;
48 __PACKAGE__->register_method(
49 method => "set_user_settings",
50 api_name => "open-ils.actor.patron.settings.update",
52 sub set_user_settings {
53 my( $self, $client, $user_session, $uid, $settings ) = @_;
55 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
57 my( $staff, $user, $evt ) =
58 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
63 # [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
66 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
68 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
70 return $apputils->simplereq(
72 'open-ils.storage.direct.actor.user_setting.batch.merge', @params );
78 __PACKAGE__->register_method(
79 method => "set_ou_settings",
80 api_name => "open-ils.actor.org_unit.settings.update",
83 my( $self, $client, $user_session, $ouid, $settings ) = @_;
85 my( $staff, $evt ) = $apputils->checkses( $user_session );
87 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
92 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
94 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper($params));
96 return $apputils->simplereq(
98 'open-ils.storage.direct.actor.org_unit_setting.merge', @$params );
102 my $fetch_user_settings;
103 my $fetch_ou_settings;
105 __PACKAGE__->register_method(
106 method => "user_settings",
107 api_name => "open-ils.actor.patron.settings.retrieve",
110 my( $self, $client, $user_session, $uid ) = @_;
112 my( $staff, $user, $evt ) =
113 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
116 $logger->debug("User " . $staff->id . " fetching user $uid\n");
117 my $s = $apputils->simplereq(
119 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
121 return { map { ($_->name,$_->value) } @$s };
126 __PACKAGE__->register_method(
127 method => "ou_settings",
128 api_name => "open-ils.actor.org_unit.settings.retrieve",
131 my( $self, $client, $ouid ) = @_;
133 $logger->info("Fetching org unit settings for org $ouid");
135 my $s = $apputils->simplereq(
137 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
139 return { map { ($_->name,$_->value) } @$s };
142 __PACKAGE__->register_method (
143 method => "ou_setting_delete",
144 api_name => 'open-ils.actor.org_setting.delete',
146 Deletes a specific org unit setting for a specific location
147 @param authtoken The login session key
148 @param orgid The org unit whose setting we're changing
149 @param setting The name of the setting to delete
150 @return True value on success.
154 sub ou_setting_delete {
155 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
156 my( $reqr, $evt) = $U->checkses($authtoken);
158 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
161 my $id = $U->storagereq(
162 'open-ils.storage.id_list.actor.org_unit_setting.search_where',
163 { name => $setting, org_unit => $orgid } );
165 $logger->debug("Retrieved setting $id in org unit setting delete");
167 my $s = $U->storagereq(
168 'open-ils.storage.direct.actor.org_unit_setting.delete', $id );
170 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
176 __PACKAGE__->register_method(
177 method => "update_patron",
178 api_name => "open-ils.actor.patron.update",);
181 my( $self, $client, $user_session, $patron ) = @_;
183 my $session = $apputils->start_db_session();
186 $logger->info("Creating new patron...") if $patron->isnew;
187 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
189 my( $user_obj, $evt ) = $U->checkses($user_session);
192 # XXX does this user have permission to add/create users. Granularity?
193 # $new_patron is the patron in progress. $patron is the original patron
194 # passed in with the method. new_patron will change as the components
195 # of patron are added/updated.
199 # unflesh the real items on the patron
200 $patron->card( $patron->card->id ) if(ref($patron->card));
201 $patron->billing_address( $patron->billing_address->id )
202 if(ref($patron->billing_address));
203 $patron->mailing_address( $patron->mailing_address->id )
204 if(ref($patron->mailing_address));
206 # create/update the patron first so we can use his id
207 if($patron->isnew()) {
208 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
210 } else { $new_patron = $patron; }
212 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
215 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
218 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
221 # re-update the patron if anything has happened to him during this process
222 if($new_patron->ischanged()) {
223 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
227 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
229 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
232 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
235 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
238 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
239 $apputils->commit_db_session($session);
241 #warn "Patron Update/Create complete\n";
242 return flesh_user($new_patron->id());
248 __PACKAGE__->register_method(
249 method => "user_retrieve_fleshed_by_id",
250 api_name => "open-ils.actor.user.fleshed.retrieve",);
252 sub user_retrieve_fleshed_by_id {
253 my( $self, $client, $user_session, $user_id ) = @_;
255 my( $requestor, $target, $evt ) = $apputils->
256 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
259 return flesh_user($user_id);
263 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
271 $session = OpenSRF::AppSession->create("open-ils.storage");
275 # grab the user with the given id
276 my $ureq = $session->request(
277 "open-ils.storage.direct.actor.user.retrieve", $id);
278 my $user = $ureq->gather(1);
280 if(!$user) { return undef; }
283 my $cards_req = $session->request(
284 "open-ils.storage.direct.actor.card.search.usr.atomic",
286 $user->cards( $cards_req->gather(1) );
288 for my $c(@{$user->cards}) {
289 if($c->id == $user->card || $c->id eq $user->card ) {
290 #warn "Setting my card to " . $c->id . "\n";
295 my $add_req = $session->request(
296 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
298 $user->addresses( $add_req->gather(1) );
300 if( @{$user->addresses} ) {
301 if( ! grep { $_->id eq $user->billing_address } @{$user->addresses} ) {
302 my $ba = $session->request(
303 'open-ils.storage.direct.actor.user_address.retrieve',
304 $user->billing_address)->gather(1);
305 push( @{$user->addresses}, $ba );
308 if( ! grep { $_->id eq $user->mailing_address } @{$user->addresses} ) {
309 my $ba = $session->request(
310 'open-ils.storage.direct.actor.user_address.retrieve',
311 $user->mailing_address)->gather(1);
312 push( @{$user->addresses}, $ba );
317 for my $c(@{$user->addresses}) {
318 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
319 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
322 my $stat_req = $session->request(
323 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
325 $user->stat_cat_entries($stat_req->gather(1));
327 my $standing_penalties_req = $session->request(
328 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
330 $user->standing_penalties($standing_penalties_req->gather(1));
332 if($kill) { $session->disconnect(); }
333 $user->clear_passwd();
339 # clone and clear stuff that would break the database
343 my $new_patron = $patron->clone;
345 # Using the Fieldmapper clone method
346 #my $new_patron = Fieldmapper::actor::user->new();
348 #my $fmap = $Fieldmapper::fieldmap;
349 #no strict; # shallow clone, may be useful in the fieldmapper
351 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
352 # $new_patron->$field( $patron->$field() );
357 $new_patron->clear_billing_address();
358 $new_patron->clear_mailing_address();
359 $new_patron->clear_addresses();
360 $new_patron->clear_card();
361 $new_patron->clear_cards();
362 $new_patron->clear_id();
363 $new_patron->clear_isnew();
364 $new_patron->clear_ischanged();
365 $new_patron->clear_isdeleted();
366 $new_patron->clear_stat_cat_entries();
367 $new_patron->clear_permissions();
368 $new_patron->clear_standing_penalties();
378 my $user_obj = shift;
380 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
381 return (undef, $evt) if $evt;
383 my $ex = $session->request(
384 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
386 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
389 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
391 my $id = $session->request(
392 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
393 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
395 $logger->info("Successfully created new user [$id] in DB");
397 return ( $session->request(
398 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
403 my( $session, $patron, $user_obj, $noperm) = @_;
405 $logger->info("Updating patron ".$patron->id." in DB");
408 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
409 return (undef, $evt) if $evt;
412 # update the password by itself to avoid the password protection magic
413 if( $patron->passwd ) {
414 my $s = $session->request(
415 'open-ils.storage.direct.actor.user.remote_update',
416 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
417 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
418 $patron->clear_passwd;
421 if(!$patron->ident_type) {
422 $patron->clear_ident_type;
423 $patron->clear_ident_value;
426 if(!$patron->ident_type2) {
427 $patron->clear_ident_type2;
428 $patron->clear_ident_value2;
431 my $stat = $session->request(
432 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
433 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
439 sub _add_update_addresses {
443 my $new_patron = shift;
447 my $current_id; # id of the address before creation
449 for my $address (@{$patron->addresses()}) {
451 next unless ref $address;
452 $current_id = $address->id();
454 if( $patron->billing_address() and
455 $patron->billing_address() == $current_id ) {
456 $logger->info("setting billing addr to $current_id");
457 $new_patron->billing_address($address->id());
458 $new_patron->ischanged(1);
461 if( $patron->mailing_address() and
462 $patron->mailing_address() == $current_id ) {
463 $new_patron->mailing_address($address->id());
464 $logger->info("setting mailing addr to $current_id");
465 $new_patron->ischanged(1);
469 if($address->isnew()) {
471 $address->usr($new_patron->id());
473 ($address, $evt) = _add_address($session,$address);
474 return (undef, $evt) if $evt;
476 # we need to get the new id
477 if( $patron->billing_address() and
478 $patron->billing_address() == $current_id ) {
479 $new_patron->billing_address($address->id());
480 $logger->info("setting billing addr to $current_id");
481 $new_patron->ischanged(1);
484 if( $patron->mailing_address() and
485 $patron->mailing_address() == $current_id ) {
486 $new_patron->mailing_address($address->id());
487 $logger->info("setting mailing addr to $current_id");
488 $new_patron->ischanged(1);
491 } elsif($address->ischanged() ) {
493 ($address, $evt) = _update_address($session, $address);
494 return (undef, $evt) if $evt;
496 } elsif($address->isdeleted() ) {
498 if( $address->id() == $new_patron->mailing_address() ) {
499 $new_patron->clear_mailing_address();
500 ($new_patron, $evt) = _update_patron($session, $new_patron);
501 return (undef, $evt) if $evt;
504 if( $address->id() == $new_patron->billing_address() ) {
505 $new_patron->clear_billing_address();
506 ($new_patron, $evt) = _update_patron($session, $new_patron);
507 return (undef, $evt) if $evt;
510 $evt = _delete_address($session, $address);
511 return (undef, $evt) if $evt;
515 return ( $new_patron, undef );
519 # adds an address to the db and returns the address with new id
521 my($session, $address) = @_;
522 $address->clear_id();
524 $logger->info("Creating new address at street ".$address->street1);
526 # put the address into the database
527 my $id = $session->request(
528 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
529 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
532 return ($address, undef);
536 sub _update_address {
537 my( $session, $address ) = @_;
539 $logger->info("Updating address ".$address->id." in the DB");
541 my $stat = $session->request(
542 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
544 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
545 return ($address, undef);
550 sub _add_update_cards {
554 my $new_patron = shift;
558 my $virtual_id; #id of the card before creation
559 for my $card (@{$patron->cards()}) {
561 $card->usr($new_patron->id());
563 if(ref($card) and $card->isnew()) {
565 $virtual_id = $card->id();
566 ( $card, $evt ) = _add_card($session,$card);
567 return (undef, $evt) if $evt;
569 #if(ref($patron->card)) { $patron->card($patron->card->id); }
570 if($patron->card() == $virtual_id) {
571 $new_patron->card($card->id());
572 $new_patron->ischanged(1);
575 } elsif( ref($card) and $card->ischanged() ) {
576 $evt = _update_card($session, $card);
577 return (undef, $evt) if $evt;
581 return ( $new_patron, undef );
585 # adds an card to the db and returns the card with new id
587 my( $session, $card ) = @_;
590 $logger->info("Adding new patron card ".$card->barcode);
592 my $id = $session->request(
593 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
594 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
595 $logger->info("Successfully created patron card $id");
598 return ( $card, undef );
602 # returns event on error. returns undef otherwise
604 my( $session, $card ) = @_;
605 $logger->info("Updating patron card ".$card->id);
607 my $stat = $session->request(
608 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
609 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
616 # returns event on error. returns undef otherwise
617 sub _delete_address {
618 my( $session, $address ) = @_;
620 $logger->info("Deleting address ".$address->id." from DB");
622 my $stat = $session->request(
623 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
625 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
631 sub _add_survey_responses {
632 my ($session, $patron, $new_patron) = @_;
634 $logger->info( "Updating survey responses for patron ".$new_patron->id );
636 my $responses = $patron->survey_responses;
640 $_->usr($new_patron->id) for (@$responses);
642 my $evt = $U->simplereq( "open-ils.circ",
643 "open-ils.circ.survey.submit.user_id", $responses );
645 return (undef, $evt) if defined($U->event_code($evt));
649 return ( $new_patron, undef );
653 sub _create_stat_maps {
655 my($session, $user_session, $patron, $new_patron) = @_;
657 my $maps = $patron->stat_cat_entries();
659 for my $map (@$maps) {
661 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
663 if ($map->isdeleted()) {
664 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
666 } elsif ($map->isnew()) {
667 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
672 $map->target_usr($new_patron->id);
675 $logger->info("Updating stat entry with method $method and map $map");
677 my $stat = $session->request($method, $map)->gather(1);
678 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
682 return ($new_patron, undef);
685 sub _create_perm_maps {
687 my($session, $user_session, $patron, $new_patron) = @_;
689 my $maps = $patron->permissions;
691 for my $map (@$maps) {
693 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
694 if ($map->isdeleted()) {
695 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
696 } elsif ($map->isnew()) {
697 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
702 $map->usr($new_patron->id);
704 #warn( "Updating permissions with method $method and session $user_session and map $map" );
705 $logger->info( "Updating permissions with method $method and map $map" );
707 my $stat = $session->request($method, $map)->gather(1);
708 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
712 return ($new_patron, undef);
716 sub _create_standing_penalties {
718 my($session, $user_session, $patron, $new_patron) = @_;
720 my $maps = $patron->standing_penalties;
723 for my $map (@$maps) {
725 if ($map->isdeleted()) {
726 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
727 } elsif ($map->isnew()) {
728 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
734 $map->usr($new_patron->id);
736 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
738 my $stat = $session->request($method, $map)->gather(1);
739 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
742 return ($new_patron, undef);
747 __PACKAGE__->register_method(
748 method => "search_username",
749 api_name => "open-ils.actor.user.search.username",
752 sub search_username {
753 my($self, $client, $username) = @_;
754 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
756 "open-ils.storage.direct.actor.user.search.usrname.atomic",
764 __PACKAGE__->register_method(
765 method => "user_retrieve_by_barcode",
766 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
768 sub user_retrieve_by_barcode {
769 my($self, $client, $user_session, $barcode) = @_;
771 $logger->debug("Searching for user with barcode $barcode");
772 my ($user_obj, $evt) = $apputils->checkses($user_session);
776 my $session = OpenSRF::AppSession->create("open-ils.storage");
778 # find the card with the given barcode
779 my $creq = $session->request(
780 "open-ils.storage.direct.actor.card.search.barcode.atomic",
782 my $card = $creq->gather(1);
784 if(!$card || !$card->[0]) {
785 $session->disconnect();
786 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
790 my $user = flesh_user($card->usr(), $session);
792 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
795 $session->disconnect();
796 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
803 __PACKAGE__->register_method(
804 method => "get_user_by_id",
805 api_name => "open-ils.actor.user.retrieve",);
808 my ($self, $client, $user_session, $id) = @_;
810 my $user_obj = $apputils->check_user_session( $user_session );
812 return $apputils->simple_scalar_request(
814 "open-ils.storage.direct.actor.user.retrieve",
820 __PACKAGE__->register_method(
821 method => "get_org_types",
822 api_name => "open-ils.actor.org_types.retrieve",);
826 my($self, $client) = @_;
828 return $org_types if $org_types;
830 $apputils->simple_scalar_request(
832 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
837 __PACKAGE__->register_method(
838 method => "get_user_profiles",
839 api_name => "open-ils.actor.user.profiles.retrieve",
843 sub get_user_profiles {
844 return $user_profiles if $user_profiles;
846 return $user_profiles =
847 $apputils->simple_scalar_request(
849 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
854 __PACKAGE__->register_method(
855 method => "get_user_ident_types",
856 api_name => "open-ils.actor.user.ident_types.retrieve",
859 sub get_user_ident_types {
860 return $ident_types if $ident_types;
861 return $ident_types =
862 $apputils->simple_scalar_request(
864 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
870 __PACKAGE__->register_method(
871 method => "get_org_unit",
872 api_name => "open-ils.actor.org_unit.retrieve",
876 my( $self, $client, $user_session, $org_id ) = @_;
877 my $e = new_editor(authtoken => $user_session);
879 return $e->event unless $e->checkauth;
880 $org_id = $e->requestor->ws_ou;
882 my $o = $e->retrieve_actor_org_unit($org_id)
887 __PACKAGE__->register_method(
888 method => "search_org_unit",
889 api_name => "open-ils.actor.org_unit_list.search",
892 sub search_org_unit {
894 my( $self, $client, $field, $value ) = @_;
896 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
898 "open-ils.storage.direct.actor.org_unit.search.$field.atomic",
907 __PACKAGE__->register_method(
908 method => "get_org_tree",
909 api_name => "open-ils.actor.org_tree.retrieve",
911 note => "Returns the entire org tree structure",
915 my( $self, $client) = @_;
918 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
920 # see if it's in the cache
921 #warn "Getting ORG Tree\n";
922 my $tree = $cache_client->get_cache('orgtree');
924 #warn "Found orgtree in cache. returning...\n";
928 my $orglist = $apputils->simple_scalar_request(
930 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
933 #warn "found org list\n";
936 $tree = $self->build_org_tree($orglist);
937 $cache_client->put_cache('orgtree', $tree);
943 # turns an org list into an org tree
946 my( $self, $orglist) = @_;
948 return $orglist unless (
949 ref($orglist) and @$orglist > 1 );
952 $a->ou_type <=> $b->ou_type ||
953 $a->name cmp $b->name } @$orglist;
955 for my $org (@list) {
957 next unless ($org and defined($org->parent_ou));
958 my ($parent) = grep { $_->id == $org->parent_ou } @list;
961 $parent->children([]) unless defined($parent->children);
962 push( @{$parent->children}, $org );
970 __PACKAGE__->register_method(
971 method => "get_org_descendants",
972 api_name => "open-ils.actor.org_tree.descendants.retrieve"
975 # depth is optional. org_unit is the id
976 sub get_org_descendants {
977 my( $self, $client, $org_unit, $depth ) = @_;
978 my $orglist = $apputils->simple_scalar_request(
980 "open-ils.storage.actor.org_unit.descendants.atomic",
982 return $self->build_org_tree($orglist);
986 __PACKAGE__->register_method(
987 method => "get_org_ancestors",
988 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
991 # depth is optional. org_unit is the id
992 sub get_org_ancestors {
993 my( $self, $client, $org_unit, $depth ) = @_;
994 my $orglist = $apputils->simple_scalar_request(
996 "open-ils.storage.actor.org_unit.ancestors.atomic",
998 return $self->build_org_tree($orglist);
1002 __PACKAGE__->register_method(
1003 method => "get_standings",
1004 api_name => "open-ils.actor.standings.retrieve"
1009 return $user_standings if $user_standings;
1010 return $user_standings =
1011 $apputils->simple_scalar_request(
1013 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
1018 __PACKAGE__->register_method(
1019 method => "get_my_org_path",
1020 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1023 sub get_my_org_path {
1024 my( $self, $client, $user_session, $org_id ) = @_;
1025 my $user_obj = $apputils->check_user_session($user_session);
1026 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1028 return $apputils->simple_scalar_request(
1030 "open-ils.storage.actor.org_unit.full_path.atomic",
1035 __PACKAGE__->register_method(
1036 method => "patron_adv_search",
1037 api_name => "open-ils.actor.patron.search.advanced" );
1038 sub patron_adv_search {
1039 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1040 my $e = OpenILS::Utils::Editor->new(authtoken=>$auth);
1041 return $e->event unless $e->checkauth;
1042 return $e->event unless $e->allowed('VIEW_USER');
1044 "open-ils.storage.actor.user.crazy_search",
1045 $search_hash, $search_limit, $search_sort);
1050 sub _verify_password {
1051 my($user_session, $password) = @_;
1052 my $user_obj = $apputils->check_user_session($user_session);
1054 #grab the user with password
1055 $user_obj = $apputils->simple_scalar_request(
1057 "open-ils.storage.direct.actor.user.retrieve",
1060 if($user_obj->passwd eq $password) {
1068 __PACKAGE__->register_method(
1069 method => "update_password",
1070 api_name => "open-ils.actor.user.password.update");
1072 __PACKAGE__->register_method(
1073 method => "update_password",
1074 api_name => "open-ils.actor.user.username.update");
1076 __PACKAGE__->register_method(
1077 method => "update_password",
1078 api_name => "open-ils.actor.user.email.update");
1080 sub update_password {
1081 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1085 my $user_obj = $apputils->check_user_session($user_session);
1087 if($self->api_name =~ /password/o) {
1089 #make sure they know the current password
1090 if(!_verify_password($user_session, md5_hex($current_password))) {
1091 return OpenILS::Event->new('INCORRECT_PASSWORD');
1094 $logger->debug("update_password setting new password $new_value");
1095 $user_obj->passwd($new_value);
1097 } elsif($self->api_name =~ /username/o) {
1098 my $users = search_username(undef, undef, $new_value);
1099 if( $users and $users->[0] ) {
1100 return OpenILS::Event->new('USERNAME_EXISTS');
1102 $user_obj->usrname($new_value);
1104 } elsif($self->api_name =~ /email/o) {
1105 #warn "Updating email to $new_value\n";
1106 $user_obj->email($new_value);
1109 my $session = $apputils->start_db_session();
1111 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1112 return $evt if $evt;
1114 $apputils->commit_db_session($session);
1116 if($user_obj) { return 1; }
1121 __PACKAGE__->register_method(
1122 method => "check_user_perms",
1123 api_name => "open-ils.actor.user.perm.check",
1124 notes => <<" NOTES");
1125 Takes a login session, user id, an org id, and an array of perm type strings. For each
1126 perm type, if the user does *not* have the given permission it is added
1127 to a list which is returned from the method. If all permissions
1128 are allowed, an empty list is returned
1129 if the logged in user does not match 'user_id', then the logged in user must
1130 have VIEW_PERMISSION priveleges.
1133 sub check_user_perms {
1134 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1136 my( $staff, $evt ) = $apputils->checkses($login_session);
1137 return $evt if $evt;
1139 if($staff->id ne $user_id) {
1140 if( my $evt = $apputils->check_perms(
1141 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1147 for my $perm (@$perm_types) {
1148 if($apputils->check_perms($user_id, $org_id, $perm)) {
1149 push @not_allowed, $perm;
1153 return \@not_allowed
1156 __PACKAGE__->register_method(
1157 method => "check_user_perms2",
1158 api_name => "open-ils.actor.user.perm.check.multi_org",
1160 Checks the permissions on a list of perms and orgs for a user
1161 @param authtoken The login session key
1162 @param user_id The id of the user to check
1163 @param orgs The array of org ids
1164 @param perms The array of permission names
1165 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1166 if the logged in user does not match 'user_id', then the logged in user must
1167 have VIEW_PERMISSION priveleges.
1170 sub check_user_perms2 {
1171 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1173 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1174 $authtoken, $user_id, 'VIEW_PERMISSION' );
1175 return $evt if $evt;
1178 for my $org (@$orgs) {
1179 for my $perm (@$perms) {
1180 if($apputils->check_perms($user_id, $org, $perm)) {
1181 push @not_allowed, [ $org, $perm ];
1186 return \@not_allowed
1190 __PACKAGE__->register_method(
1191 method => 'check_user_perms3',
1192 api_name => 'open-ils.actor.user.perm.highest_org',
1194 Returns the highest org unit id at which a user has a given permission
1195 If the requestor does not match the target user, the requestor must have
1196 'VIEW_PERMISSION' rights at the home org unit of the target user
1197 @param authtoken The login session key
1198 @param userid The id of the user in question
1199 @param perm The permission to check
1200 @return The org unit highest in the org tree within which the user has
1201 the requested permission
1204 sub check_user_perms3 {
1205 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1207 my( $staff, $target, $org, $evt );
1209 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1210 $authtoken, $userid, 'VIEW_PERMISSION' );
1211 return $evt if $evt;
1213 my $tree = $self->get_org_tree();
1214 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1218 sub _find_highest_perm_org {
1219 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1220 my $org = $apputils->find_org($org_tree, $start_org );
1224 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1226 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1232 __PACKAGE__->register_method(
1233 method => 'check_user_perms4',
1234 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1236 Returns the highest org unit id at which a user has a given permission
1237 If the requestor does not match the target user, the requestor must have
1238 'VIEW_PERMISSION' rights at the home org unit of the target user
1239 @param authtoken The login session key
1240 @param userid The id of the user in question
1241 @param perms An array of perm names to check
1242 @return An array of orgId's representing the org unit
1243 highest in the org tree within which the user has the requested permission
1244 The arrah of orgId's has matches the order of the perms array
1247 sub check_user_perms4 {
1248 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1250 my( $staff, $target, $org, $evt );
1252 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1253 $authtoken, $userid, 'VIEW_PERMISSION' );
1254 return $evt if $evt;
1257 return [] unless ref($perms);
1258 my $tree = $self->get_org_tree();
1260 for my $p (@$perms) {
1261 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1269 __PACKAGE__->register_method(
1270 method => "user_fines_summary",
1271 api_name => "open-ils.actor.user.fines.summary",
1272 notes => <<" NOTES");
1273 Returns a short summary of the users total open fines, excluding voided fines
1274 Params are login_session, user_id
1275 Returns a 'mous' object.
1278 sub user_fines_summary {
1279 my( $self, $client, $login_session, $user_id ) = @_;
1281 my $user_obj = $apputils->check_user_session($login_session);
1282 if($user_obj->id ne $user_id) {
1283 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1284 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1288 return $apputils->simple_scalar_request(
1290 "open-ils.storage.direct.money.open_user_summary.search.usr",
1298 __PACKAGE__->register_method(
1299 method => "user_transactions",
1300 api_name => "open-ils.actor.user.transactions",
1301 notes => <<" NOTES");
1302 Returns a list of open user transactions (mbts objects);
1303 Params are login_session, user_id
1304 Optional third parameter is the transactions type. defaults to all
1307 __PACKAGE__->register_method(
1308 method => "user_transactions",
1309 api_name => "open-ils.actor.user.transactions.have_charge",
1310 notes => <<" NOTES");
1311 Returns a list of all open user transactions (mbts objects) that have an initial charge
1312 Params are login_session, user_id
1313 Optional third parameter is the transactions type. defaults to all
1316 __PACKAGE__->register_method(
1317 method => "user_transactions",
1318 api_name => "open-ils.actor.user.transactions.have_balance",
1319 notes => <<" NOTES");
1320 Returns a list of all open user transactions (mbts objects) that have a balance
1321 Params are login_session, user_id
1322 Optional third parameter is the transactions type. defaults to all
1325 __PACKAGE__->register_method(
1326 method => "user_transactions",
1327 api_name => "open-ils.actor.user.transactions.fleshed",
1328 notes => <<" NOTES");
1329 Returns an object/hash of transaction, circ, title where transaction = an open
1330 user transactions (mbts objects), circ is the attached circluation, and title
1331 is the title the circ points to
1332 Params are login_session, user_id
1333 Optional third parameter is the transactions type. defaults to all
1336 __PACKAGE__->register_method(
1337 method => "user_transactions",
1338 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1339 notes => <<" NOTES");
1340 Returns an object/hash of transaction, circ, title where transaction = an open
1341 user transactions that has an initial charge (mbts objects), circ is the
1342 attached circluation, and title is the title the circ points to
1343 Params are login_session, user_id
1344 Optional third parameter is the transactions type. defaults to all
1347 __PACKAGE__->register_method(
1348 method => "user_transactions",
1349 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1350 notes => <<" NOTES");
1351 Returns an object/hash of transaction, circ, title where transaction = an open
1352 user transaction that has a balance (mbts objects), circ is the attached
1353 circluation, and title is the title the circ points to
1354 Params are login_session, user_id
1355 Optional third parameter is the transaction type. defaults to all
1358 __PACKAGE__->register_method(
1359 method => "user_transactions",
1360 api_name => "open-ils.actor.user.transactions.count",
1361 notes => <<" NOTES");
1362 Returns an object/hash of transaction, circ, title where transaction = an open
1363 user transactions (mbts objects), circ is the attached circluation, and title
1364 is the title the circ points to
1365 Params are login_session, user_id
1366 Optional third parameter is the transactions type. defaults to all
1369 __PACKAGE__->register_method(
1370 method => "user_transactions",
1371 api_name => "open-ils.actor.user.transactions.have_charge.count",
1372 notes => <<" NOTES");
1373 Returns an object/hash of transaction, circ, title where transaction = an open
1374 user transactions that has an initial charge (mbts objects), circ is the
1375 attached circluation, and title is the title the circ points to
1376 Params are login_session, user_id
1377 Optional third parameter is the transactions type. defaults to all
1380 __PACKAGE__->register_method(
1381 method => "user_transactions",
1382 api_name => "open-ils.actor.user.transactions.have_balance.count",
1383 notes => <<" NOTES");
1384 Returns an object/hash of transaction, circ, title where transaction = an open
1385 user transaction that has a balance (mbts objects), circ is the attached
1386 circluation, and title is the title the circ points to
1387 Params are login_session, user_id
1388 Optional third parameter is the transaction type. defaults to all
1391 __PACKAGE__->register_method(
1392 method => "user_transactions",
1393 api_name => "open-ils.actor.user.transactions.have_balance.total",
1394 notes => <<" NOTES");
1395 Returns an object/hash of transaction, circ, title where transaction = an open
1396 user transaction that has a balance (mbts objects), circ is the attached
1397 circluation, and title is the title the circ points to
1398 Params are login_session, user_id
1399 Optional third parameter is the transaction type. defaults to all
1404 sub user_transactions {
1405 my( $self, $client, $login_session, $user_id, $type ) = @_;
1407 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1408 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1409 return $evt if $evt;
1411 my $api = $self->api_name();
1415 if(defined($type)) { @xact = (xact_type => $type);
1417 } else { @xact = (); }
1419 if($api =~ /have_charge/o) {
1421 $trans = $apputils->simple_scalar_request(
1423 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1424 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1426 } elsif($api =~ /have_balance/o) {
1428 $trans = $apputils->simple_scalar_request(
1430 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1431 { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1435 $trans = $apputils->simple_scalar_request(
1437 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1438 { usr => $user_id, @xact });
1441 if($api =~ /total/o) {
1443 for my $t (@$trans) {
1444 $total += $t->balance_owed;
1447 $logger->debug("Total balance owed by user $user_id: $total");
1451 if($api =~ /count/o) { return scalar @$trans; }
1452 if($api !~ /fleshed/o) { return $trans; }
1455 for my $t (@$trans) {
1457 if( $t->xact_type ne 'circulation' ) {
1458 push @resp, {transaction => $t};
1462 my $circ = $apputils->simple_scalar_request(
1464 "open-ils.storage.direct.action.circulation.retrieve",
1469 my $title = $apputils->simple_scalar_request(
1471 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1472 $circ->target_copy );
1476 my $u = OpenILS::Utils::ModsParser->new();
1477 $u->start_mods_batch($title->marc());
1478 my $mods = $u->finish_mods_batch();
1480 push @resp, {transaction => $t, circ => $circ, record => $mods };
1488 __PACKAGE__->register_method(
1489 method => "user_transaction_retrieve",
1490 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1492 notes => <<" NOTES");
1493 Returns a fleshedtransaction record
1495 __PACKAGE__->register_method(
1496 method => "user_transaction_retrieve",
1497 api_name => "open-ils.actor.user.transaction.retrieve",
1499 notes => <<" NOTES");
1500 Returns a transaction record
1502 sub user_transaction_retrieve {
1503 my( $self, $client, $login_session, $bill_id ) = @_;
1505 my $trans = $apputils->simple_scalar_request(
1507 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1511 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1512 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1513 return $evt if $evt;
1515 my $api = $self->api_name();
1516 if($api !~ /fleshed/o) { return $trans; }
1518 if( $trans->xact_type ne 'circulation' ) {
1519 $logger->debug("Returning non-circ transaction");
1520 return {transaction => $trans};
1523 my $circ = $apputils->simple_scalar_request(
1525 "open-ils.storage.direct.action.circulation.retrieve",
1528 return {transaction => $trans} unless $circ;
1529 $logger->debug("Found the circ transaction");
1531 my $title = $apputils->simple_scalar_request(
1533 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1534 $circ->target_copy );
1536 return {transaction => $trans, circ => $circ } unless $title;
1537 $logger->debug("Found the circ title");
1541 my $u = OpenILS::Utils::ModsParser->new();
1542 $u->start_mods_batch($title->marc());
1543 $mods = $u->finish_mods_batch();
1545 if ($title->id == -1) {
1546 my $copy = $apputils->simple_scalar_request(
1548 "open-ils.storage.direct.asset.copy.retrieve",
1549 $circ->target_copy );
1551 $mods = new Fieldmapper::metabib::virtual_record;
1553 $mods->title($copy->dummy_title);
1554 $mods->author($copy->dummy_author);
1558 $logger->debug("MODSized the circ title");
1560 return {transaction => $trans, circ => $circ, record => $mods };
1564 __PACKAGE__->register_method(
1565 method => "hold_request_count",
1566 api_name => "open-ils.actor.user.hold_requests.count",
1568 notes => <<" NOTES");
1569 Returns hold ready/total counts
1571 sub hold_request_count {
1572 my( $self, $client, $login_session, $userid ) = @_;
1574 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1575 $login_session, $userid, 'VIEW_HOLD' );
1576 return $evt if $evt;
1579 my $holds = $apputils->simple_scalar_request(
1581 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1583 fulfillment_time => {"=" => undef } }
1587 for my $h (@$holds) {
1588 next unless $h->capture_time;
1590 my $copy = $apputils->simple_scalar_request(
1592 "open-ils.storage.direct.asset.copy.retrieve",
1596 if ($copy->status == 8) {
1601 return { total => scalar(@$holds), ready => scalar(@ready) };
1605 __PACKAGE__->register_method(
1606 method => "checkedout_count",
1607 api_name => "open-ils.actor.user.checked_out.count__",
1609 notes => <<" NOTES");
1610 Returns a transaction record
1614 sub checkedout_count {
1615 my( $self, $client, $login_session, $userid ) = @_;
1617 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1618 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1619 return $evt if $evt;
1621 my $circs = $apputils->simple_scalar_request(
1623 "open-ils.storage.direct.action.circulation.search_where.atomic",
1624 { usr => $userid, stop_fines => undef }
1625 #{ usr => $userid, checkin_time => {"=" => undef } }
1628 my $parser = DateTime::Format::ISO8601->new;
1631 for my $c (@$circs) {
1632 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1633 my $due = $due_dt->epoch;
1635 if ($due < DateTime->today->epoch) {
1640 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1644 __PACKAGE__->register_method(
1645 method => "checked_out",
1646 api_name => "open-ils.actor.user.checked_out",
1649 Returns a structure of circulations objects sorted by
1650 out, overdue, lost, claims_returned, long_overdue.
1651 A list of IDs are returned of each type.
1652 lost, long_overdue, and claims_returned circ will not
1653 be "finished" (there is an outstanding balance or some
1654 other pending action on the circ).
1656 The .count method also includes a 'total' field which
1657 sums all "open" circs
1661 __PACKAGE__->register_method(
1662 method => "checked_out",
1663 api_name => "open-ils.actor.user.checked_out.count",
1665 signature => q/@see open-ils.actor.user.checked_out/
1669 my( $self, $conn, $auth, $userid ) = @_;
1671 my $e = new_editor(authtoken=>$auth);
1672 return $e->event unless $e->checkauth;
1674 if( $userid ne $e->requestor->id ) {
1675 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1678 my $count = $self->api_name =~ /count/;
1679 return _checked_out( $count, $e, $userid );
1683 my( $iscount, $e, $userid ) = @_;
1685 my $circs = $e->search_action_circulation(
1686 { usr => $userid, stop_fines => undef });
1688 my $parser = DateTime::Format::ISO8601->new;
1690 # split the circs up into overdue and not-overdue circs
1692 for my $c (@$circs) {
1693 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1694 my $due = $due_dt->epoch;
1695 if ($due < DateTime->today->epoch) {
1696 push @overdue, $c->id;
1702 # grab all of the lost, claims-returned, and longoverdue circs
1703 my $open = $e->search_action_circulation(
1704 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1706 my( @lost, @cr, @lo );
1707 for my $c (@$open) {
1708 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1709 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1710 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1716 total => @$circs + @lost + @cr + @lo,
1717 out => scalar(@out),
1718 overdue => scalar(@overdue),
1719 lost => scalar(@lost),
1720 claims_returned => scalar(@cr),
1721 long_overdue => scalar(@lo)
1727 overdue => \@overdue,
1729 claims_returned => \@cr,
1730 long_overdue => \@lo
1738 __PACKAGE__->register_method(
1739 method => "user_transaction_history",
1740 api_name => "open-ils.actor.user.transactions.history",
1742 notes => <<" NOTES");
1743 Returns a list of billable transaction ids for a user, optionally by type
1745 __PACKAGE__->register_method(
1746 method => "user_transaction_history",
1747 api_name => "open-ils.actor.user.transactions.history.have_charge",
1749 notes => <<" NOTES");
1750 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1752 __PACKAGE__->register_method(
1753 method => "user_transaction_history",
1754 api_name => "open-ils.actor.user.transactions.history.have_balance",
1756 notes => <<" NOTES");
1757 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1761 sub _user_transaction_history {
1762 my( $self, $client, $login_session, $user_id, $type ) = @_;
1764 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1765 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1766 return $evt if $evt;
1768 my $api = $self->api_name();
1773 @xact = (xact_type => $type) if(defined($type));
1774 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1775 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1777 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1779 my $trans = $apputils->simple_scalar_request(
1781 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1782 { usr => $user_id, @xact, @charge, @balance }, { order_by => 'xact_start DESC' });
1784 return [ map { $_->id } @$trans ];
1789 sub user_transaction_history {
1790 my( $self, $conn, $auth, $userid, $type ) = @_;
1791 my $e = new_editor(authtoken=>$auth);
1792 return $e->event unless $e->checkauth;
1793 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1795 my $api = $self->api_name;
1796 my @xact = (xact_type => $type) if(defined($type));
1797 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1798 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1800 return $e->search_money_billable_transaction_summary(
1802 { usr => $userid, @xact, @charge, @balance },
1803 { order_by => 'xact_start DESC' }
1809 __PACKAGE__->register_method(
1810 method => "user_perms",
1811 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1813 notes => <<" NOTES");
1814 Returns a list of permissions
1817 my( $self, $client, $authtoken, $user ) = @_;
1819 my( $staff, $evt ) = $apputils->checkses($authtoken);
1820 return $evt if $evt;
1822 $user ||= $staff->id;
1824 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1828 return $apputils->simple_scalar_request(
1830 "open-ils.storage.permission.user_perms.atomic",
1834 __PACKAGE__->register_method(
1835 method => "retrieve_perms",
1836 api_name => "open-ils.actor.permissions.retrieve",
1837 notes => <<" NOTES");
1838 Returns a list of permissions
1840 sub retrieve_perms {
1841 my( $self, $client ) = @_;
1842 return $apputils->simple_scalar_request(
1844 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1847 __PACKAGE__->register_method(
1848 method => "retrieve_groups",
1849 api_name => "open-ils.actor.groups.retrieve",
1850 notes => <<" NOTES");
1851 Returns a list of user groupss
1853 sub retrieve_groups {
1854 my( $self, $client ) = @_;
1855 return $apputils->simple_scalar_request(
1857 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1860 __PACKAGE__->register_method(
1861 method => "retrieve_org_address",
1862 api_name => "open-ils.actor.org_unit.address.retrieve",
1863 notes => <<' NOTES');
1864 Returns an org_unit address by ID
1865 @param An org_address ID
1867 sub retrieve_org_address {
1868 my( $self, $client, $id ) = @_;
1869 return $apputils->simple_scalar_request(
1871 "open-ils.storage.direct.actor.org_address.retrieve",
1876 __PACKAGE__->register_method(
1877 method => "retrieve_groups_tree",
1878 api_name => "open-ils.actor.groups.tree.retrieve",
1879 notes => <<" NOTES");
1880 Returns a list of user groups
1882 sub retrieve_groups_tree {
1883 my( $self, $client ) = @_;
1884 my $groups = $apputils->simple_scalar_request(
1886 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1887 return $self->build_group_tree($groups);
1891 # turns an org list into an org tree
1892 sub build_group_tree {
1894 my( $self, $grplist) = @_;
1896 return $grplist unless (
1897 ref($grplist) and @$grplist > 1 );
1899 my @list = sort { $a->name cmp $b->name } @$grplist;
1902 for my $grp (@list) {
1904 if ($grp and !defined($grp->parent)) {
1908 my ($parent) = grep { $_->id == $grp->parent} @list;
1910 $parent->children([]) unless defined($parent->children);
1911 push( @{$parent->children}, $grp );
1919 __PACKAGE__->register_method(
1920 method => "add_user_to_groups",
1921 api_name => "open-ils.actor.user.set_groups",
1922 notes => <<" NOTES");
1923 Adds a user to one or more permission groups
1926 sub add_user_to_groups {
1927 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1929 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1930 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1931 return $evt if $evt;
1933 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1934 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1935 return $evt if $evt;
1937 $apputils->simplereq(
1939 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1941 for my $group (@$groups) {
1942 my $link = Fieldmapper::permission::usr_grp_map->new;
1944 $link->usr($userid);
1946 my $id = $apputils->simplereq(
1948 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1954 __PACKAGE__->register_method(
1955 method => "get_user_perm_groups",
1956 api_name => "open-ils.actor.user.get_groups",
1957 notes => <<" NOTES");
1958 Retrieve a user's permission groups.
1962 sub get_user_perm_groups {
1963 my( $self, $client, $authtoken, $userid ) = @_;
1965 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1966 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
1967 return $evt if $evt;
1969 return $apputils->simplereq(
1971 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
1976 __PACKAGE__->register_method (
1977 method => 'register_workstation',
1978 api_name => 'open-ils.actor.workstation.register.override',
1979 signature => q/@see open-ils.actor.workstation.register/);
1981 __PACKAGE__->register_method (
1982 method => 'register_workstation',
1983 api_name => 'open-ils.actor.workstation.register',
1985 Registers a new workstion in the system
1986 @param authtoken The login session key
1987 @param name The name of the workstation id
1988 @param owner The org unit that owns this workstation
1989 @return The workstation id on success, WORKSTATION_NAME_EXISTS
1990 if the name is already in use.
1993 sub _register_workstation {
1994 my( $self, $connection, $authtoken, $name, $owner ) = @_;
1995 my( $requestor, $evt ) = $U->checkses($authtoken);
1996 return $evt if $evt;
1997 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
1998 return $evt if $evt;
2000 my $ws = $U->storagereq(
2001 'open-ils.storage.direct.actor.workstation.search.name', $name );
2002 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2004 $ws = Fieldmapper::actor::workstation->new;
2005 $ws->owning_lib($owner);
2008 my $id = $U->storagereq(
2009 'open-ils.storage.direct.actor.workstation.create', $ws );
2010 return $U->DB_UPDATE_FAILED($ws) unless $id;
2016 sub register_workstation {
2017 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2019 my $e = OpenILS::Utils::Editor->new(authtoken=>$authtoken, xact=>1);
2020 return $e->event unless $e->checkauth;
2021 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2022 my $existing = $e->search_actor_workstation({name => $name});
2025 if( $self->api_name =~ /override/o ) {
2026 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2027 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2029 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2033 my $ws = Fieldmapper::actor::workstation->new;
2034 $ws->owning_lib($owner);
2036 $e->create_actor_workstation($ws) or return $e->event;
2038 return $ws->id; # note: editor sets the id on the new object for us
2042 __PACKAGE__->register_method (
2043 method => 'fetch_patron_note',
2044 api_name => 'open-ils.actor.note.retrieve.all',
2046 Returns a list of notes for a given user
2047 Requestor must have VIEW_USER permission if pub==false and
2048 @param authtoken The login session key
2049 @param args Hash of params including
2050 patronid : the patron's id
2051 pub : true if retrieving only public notes
2055 sub fetch_patron_note {
2056 my( $self, $conn, $authtoken, $args ) = @_;
2057 my $patronid = $$args{patronid};
2059 my($reqr, $evt) = $U->checkses($authtoken);
2062 ($patron, $evt) = $U->fetch_user($patronid);
2063 return $evt if $evt;
2066 if( $patronid ne $reqr->id ) {
2067 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2068 return $evt if $evt;
2070 return $U->storagereq(
2071 'open-ils.storage.direct.actor.usr_note.search_where.atomic',
2072 { usr => $patronid, pub => 't' } );
2075 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2076 return $evt if $evt;
2078 return $U->storagereq(
2079 'open-ils.storage.direct.actor.usr_note.search.usr.atomic', $patronid );
2082 __PACKAGE__->register_method (
2083 method => 'create_user_note',
2084 api_name => 'open-ils.actor.note.create',
2086 Creates a new note for the given user
2087 @param authtoken The login session key
2088 @param note The note object
2091 sub create_user_note {
2092 my( $self, $conn, $authtoken, $note ) = @_;
2093 my( $reqr, $patron, $evt ) =
2094 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2095 return $evt if $evt;
2096 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2098 $note->pub('f') unless $note->pub;
2099 $note->creator($reqr->id);
2100 my $id = $U->storagereq(
2101 'open-ils.storage.direct.actor.usr_note.create', $note );
2102 return $U->DB_UPDATE_FAILED($note) unless $id;
2107 __PACKAGE__->register_method (
2108 method => 'delete_user_note',
2109 api_name => 'open-ils.actor.note.delete',
2111 Deletes a note for the given user
2112 @param authtoken The login session key
2113 @param noteid The note id
2116 sub delete_user_note {
2117 my( $self, $conn, $authtoken, $noteid ) = @_;
2119 my $note = $U->storagereq(
2120 'open-ils.storage.direct.actor.usr_note.retrieve', $noteid);
2121 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2123 my( $reqr, $patron, $evt ) =
2124 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2125 return $evt if $evt;
2126 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2128 my $stat = $U->storagereq(
2129 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2130 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2136 __PACKAGE__->register_method (
2137 method => 'create_closed_date',
2138 api_name => 'open-ils.actor.org_unit.closed_date.create',
2140 Creates a new closing entry for the given org_unit
2141 @param authtoken The login session key
2142 @param note The closed_date object
2145 sub create_closed_date {
2146 my( $self, $conn, $authtoken, $cd ) = @_;
2148 my( $user, $evt ) = $U->checkses($authtoken);
2149 return $evt if $evt;
2151 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2152 return $evt if $evt;
2154 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2156 my $id = $U->storagereq(
2157 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2158 return $U->DB_UPDATE_FAILED($cd) unless $id;
2163 __PACKAGE__->register_method (
2164 method => 'delete_closed_date',
2165 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2167 Deletes a closing entry for the given org_unit
2168 @param authtoken The login session key
2169 @param noteid The close_date id
2172 sub delete_closed_date {
2173 my( $self, $conn, $authtoken, $cd ) = @_;
2175 my( $user, $evt ) = $U->checkses($authtoken);
2176 return $evt if $evt;
2179 ($cd_obj, $evt) = fetch_closed_date($cd);
2180 return $evt if $evt;
2182 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2183 return $evt if $evt;
2185 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2187 my $stat = $U->storagereq(
2188 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2189 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2194 __PACKAGE__->register_method(
2195 method => 'usrname_exists',
2196 api_name => 'open-ils.actor.username.exists',
2198 Returns 1 if the requested username exists, returns 0 otherwise
2202 sub usrname_exists {
2203 my( $self, $conn, $auth, $usrname ) = @_;
2204 my $e = new_editor(authtoken=>$auth);
2205 return $e->event unless $e->checkauth;
2206 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2207 return $$a[0] if $a and @$a;
2211 __PACKAGE__->register_method(
2212 method => 'barcode_exists',
2213 api_name => 'open-ils.actor.barcode.exists',
2215 Returns 1 if the requested barcode exists, returns 0 otherwise
2219 sub barcode_exists {
2220 my( $self, $conn, $auth, $barcode ) = @_;
2221 my $e = new_editor(authtoken=>$auth);
2222 return $e->event unless $e->checkauth;
2223 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2224 return $$a[0] if $a and @$a;
2229 __PACKAGE__->register_method(
2230 method => 'retrieve_net_levels',
2231 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2234 sub retrieve_net_levels {
2235 my( $self, $conn, $auth ) = @_;
2236 my $e = new_editor(authtoken=>$auth);
2237 return $e->event unless $e->checkauth;
2238 return $e->retrieve_all_config_net_access_level();