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);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Application::Search::Actor;
18 use OpenILS::Utils::ModsParser;
19 use OpenSRF::Utils::Logger qw/$logger/;
20 use OpenSRF::Utils qw/:datetime/;
22 use OpenSRF::Utils::Cache;
25 use DateTime::Format::ISO8601;
27 use OpenILS::Application::Actor::Container;
30 OpenILS::Application::Actor::Container->initialize();
33 my $apputils = "OpenILS::Application::AppUtils";
36 sub _d { warn "Patron:\n" . Dumper(shift()); }
41 my $set_user_settings;
44 __PACKAGE__->register_method(
45 method => "set_user_settings",
46 api_name => "open-ils.actor.patron.settings.update",
48 sub set_user_settings {
49 my( $self, $client, $user_session, $uid, $settings ) = @_;
51 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
53 my( $staff, $user, $evt ) =
54 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
59 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
61 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper($params));
63 return $apputils->simplereq(
65 'open-ils.storage.direct.actor.user_setting.batch.merge', $params );
71 __PACKAGE__->register_method(
72 method => "set_ou_settings",
73 api_name => "open-ils.actor.org_unit.settings.update",
76 my( $self, $client, $user_session, $ouid, $settings ) = @_;
78 my( $staff, $evt ) = $apputils->checkses( $user_session );
80 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
85 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
87 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper($params));
89 return $apputils->simplereq(
91 'open-ils.storage.direct.actor.org_unit_setting.merge', @$params );
95 my $fetch_user_settings;
96 my $fetch_ou_settings;
98 __PACKAGE__->register_method(
99 method => "user_settings",
100 api_name => "open-ils.actor.patron.settings.retrieve",
103 my( $self, $client, $user_session, $uid ) = @_;
105 my( $staff, $user, $evt ) =
106 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
109 $logger->debug("User " . $staff->id . " fetching user $uid\n");
110 my $s = $apputils->simplereq(
112 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
114 return { map { ($_->name,$_->value) } @$s };
119 __PACKAGE__->register_method(
120 method => "ou_settings",
121 api_name => "open-ils.actor.org_unit.settings.retrieve",
124 my( $self, $client, $ouid ) = @_;
126 my $s = $apputils->simplereq(
128 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
130 return { map { ($_->name,$_->value) } @$s };
135 __PACKAGE__->register_method(
136 method => "update_patron",
137 api_name => "open-ils.actor.patron.update",);
140 my( $self, $client, $user_session, $patron ) = @_;
142 my $session = $apputils->start_db_session();
145 $logger->info("Creating new patron...") if $patron->isnew;
146 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
148 my( $user_obj, $evt ) = $U->checkses($user_session);
151 # XXX does this user have permission to add/create users. Granularity?
152 # $new_patron is the patron in progress. $patron is the original patron
153 # passed in with the method. new_patron will change as the components
154 # of patron are added/updated.
158 # unflesh the real items on the patron
159 $patron->card( $patron->card->id ) if(ref($patron->card));
160 $patron->billing_address( $patron->billing_address->id )
161 if(ref($patron->billing_address));
162 $patron->mailing_address( $patron->mailing_address->id )
163 if(ref($patron->mailing_address));
165 # create/update the patron first so we can use his id
166 if($patron->isnew()) {
167 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
169 } else { $new_patron = $patron; }
171 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
174 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
177 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
180 # re-update the patron if anything has happened to him during this process
181 if($new_patron->ischanged()) {
182 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
186 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
188 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
191 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
194 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
197 $apputils->commit_db_session($session);
199 #warn "Patron Update/Create complete\n";
200 return flesh_user($new_patron->id());
206 __PACKAGE__->register_method(
207 method => "user_retrieve_fleshed_by_id",
208 api_name => "open-ils.actor.user.fleshed.retrieve",);
210 sub user_retrieve_fleshed_by_id {
211 my( $self, $client, $user_session, $user_id ) = @_;
213 my( $requestor, $target, $evt ) = $apputils->
214 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
217 return flesh_user($user_id);
228 $session = OpenSRF::AppSession->create("open-ils.storage");
232 # grab the user with the given id
233 my $ureq = $session->request(
234 "open-ils.storage.direct.actor.user.retrieve", $id);
235 my $user = $ureq->gather(1);
237 if(!$user) { return undef; }
240 my $cards_req = $session->request(
241 "open-ils.storage.direct.actor.card.search.usr.atomic",
243 $user->cards( $cards_req->gather(1) );
245 for my $c(@{$user->cards}) {
246 if($c->id == $user->card || $c->id eq $user->card ) {
247 #warn "Setting my card to " . $c->id . "\n";
252 my $add_req = $session->request(
253 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
255 $user->addresses( $add_req->gather(1) );
257 for my $c(@{$user->addresses}) {
258 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
259 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
262 my $stat_req = $session->request(
263 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
265 $user->stat_cat_entries($stat_req->gather(1));
267 my $standing_penalties_req = $session->request(
268 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
270 $user->standing_penalties($standing_penalties_req->gather(1));
272 if($kill) { $session->disconnect(); }
273 $user->clear_passwd();
279 # clone and clear stuff that would break the database
283 my $new_patron = $patron->clone;
285 # Using the Fieldmapper clone method
286 #my $new_patron = Fieldmapper::actor::user->new();
288 #my $fmap = $Fieldmapper::fieldmap;
289 #no strict; # shallow clone, may be useful in the fieldmapper
291 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
292 # $new_patron->$field( $patron->$field() );
297 $new_patron->clear_billing_address();
298 $new_patron->clear_mailing_address();
299 $new_patron->clear_addresses();
300 $new_patron->clear_card();
301 $new_patron->clear_cards();
302 $new_patron->clear_id();
303 $new_patron->clear_isnew();
304 $new_patron->clear_ischanged();
305 $new_patron->clear_isdeleted();
306 $new_patron->clear_stat_cat_entries();
307 $new_patron->clear_permissions();
308 $new_patron->clear_standing_penalties();
318 my $user_obj = shift;
320 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
321 return (undef, $evt) if $evt;
323 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
325 my $id = $session->request(
326 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
327 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
329 $logger->info("Successfully created new user [$id] in DB");
331 return ( $session->request(
332 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
337 my( $session, $patron, $user_obj) = @_;
339 $logger->info("Updating patron ".$patron->id." in DB");
340 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
341 return (undef, $evt) if $evt;
343 my $stat = $session->request(
344 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
345 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
351 sub _add_update_addresses {
355 my $new_patron = shift;
359 my $current_id; # id of the address before creation
361 for my $address (@{$patron->addresses()}) {
363 $address->usr($new_patron->id());
365 if(ref($address) and $address->isnew()) {
367 $current_id = $address->id();
368 ($address, $evt) = _add_address($session,$address);
369 return (undef, $evt) if $evt;
371 if( $patron->billing_address() and
372 $patron->billing_address() == $current_id ) {
373 $new_patron->billing_address($address->id());
374 $new_patron->ischanged(1);
377 if( $patron->mailing_address() and
378 $patron->mailing_address() == $current_id ) {
379 $new_patron->mailing_address($address->id());
380 $new_patron->ischanged(1);
383 } elsif( ref($address) and $address->ischanged() ) {
385 $address->usr($new_patron->id());
386 ($address, $evt) = _update_address($session, $address);
387 return (undef, $evt) if $evt;
389 } elsif( ref($address) and $address->isdeleted() ) {
391 if( $address->id() == $new_patron->mailing_address() ) {
392 $new_patron->clear_mailing_address();
393 ($new_patron, $evt) = _update_patron($session, $new_patron);
394 return (undef, $evt) if $evt;
397 if( $address->id() == $new_patron->billing_address() ) {
398 $new_patron->clear_billing_address();
399 ($new_patron, $evt) = _update_patron($session, $new_patron);
400 return (undef, $evt) if $evt;
403 $evt = _delete_address($session, $address);
404 return (undef, $evt) if $evt;
408 return ( $new_patron, undef );
412 # adds an address to the db and returns the address with new id
414 my($session, $address) = @_;
415 $address->clear_id();
417 $logger->info("Creating new address at street ".$address->street1);
419 # put the address into the database
420 my $id = $session->request(
421 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
422 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
425 return ($address, undef);
429 sub _update_address {
430 my( $session, $address ) = @_;
431 $logger->info("Updating address ".$address->id." in the DB");
433 my $stat = $session->request(
434 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
436 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
437 return ($address, undef);
442 sub _add_update_cards {
446 my $new_patron = shift;
450 my $virtual_id; #id of the card before creation
451 for my $card (@{$patron->cards()}) {
453 $card->usr($new_patron->id());
455 if(ref($card) and $card->isnew()) {
457 $virtual_id = $card->id();
458 ( $card, $evt ) = _add_card($session,$card);
459 return (undef, $evt) if $evt;
461 #if(ref($patron->card)) { $patron->card($patron->card->id); }
462 if($patron->card() == $virtual_id) {
463 $new_patron->card($card->id());
464 $new_patron->ischanged(1);
467 } elsif( ref($card) and $card->ischanged() ) {
468 $card->usr($new_patron->id());
469 $evt = _update_card($session, $card);
470 return (undef, $evt) if $evt;
474 return ( $new_patron, undef );
478 # adds an card to the db and returns the card with new id
480 my( $session, $card ) = @_;
482 $logger->info("Adding new patron card ".$card->barcode);
484 my $id = $session->request(
485 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
486 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
487 $logger->info("Successfully created patron card $id");
490 return ( $card, undef );
494 # returns event on error. returns undef otherwise
496 my( $session, $card ) = @_;
497 $logger->info("Updating patron card ".$card->id);
499 my $stat = $session->request(
500 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
501 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
508 # returns event on error. returns undef otherwise
509 sub _delete_address {
510 my( $session, $address ) = @_;
511 $logger->info("Deleting address ".$address->id." from DB");
513 my $stat = $session->request(
514 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
516 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
522 sub _add_survey_responses {
523 my ($session, $patron, $new_patron) = @_;
525 $logger->info( "Updating survey responses for patron ".$new_patron->id );
527 my $responses = $patron->survey_responses;
531 $_->usr($new_patron->id) for (@$responses);
533 my $evt = $U->simplereq( "open-ils.circ",
534 "open-ils.circ.survey.submit.user_id", $responses );
536 return (undef, $evt) if defined($U->event_code($evt));
540 return ( $new_patron, undef );
544 sub _create_stat_maps {
546 my($session, $user_session, $patron, $new_patron) = @_;
548 my $maps = $patron->stat_cat_entries();
550 for my $map (@$maps) {
552 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
554 if ($map->isdeleted()) {
555 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
557 } elsif ($map->isnew()) {
558 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
563 $map->target_usr($new_patron->id);
566 $logger->info("Updating stat entry with method $method and map $map");
568 my $stat = $session->request($method, $map)->gather(1);
569 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
573 return ($new_patron, undef);
576 sub _create_perm_maps {
578 my($session, $user_session, $patron, $new_patron) = @_;
580 my $maps = $patron->permissions;
582 for my $map (@$maps) {
584 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
585 if ($map->isdeleted()) {
586 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
587 } elsif ($map->isnew()) {
588 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
593 $map->usr($new_patron->id);
595 #warn( "Updating permissions with method $method and session $user_session and map $map" );
596 $logger->info( "Updating permissions with method $method and map $map" );
598 my $stat = $session->request($method, $map)->gather(1);
599 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
603 return ($new_patron, undef);
607 sub _create_standing_penalties {
609 my($session, $user_session, $patron, $new_patron) = @_;
611 my $maps = $patron->standing_penalties;
614 for my $map (@$maps) {
616 if ($map->isdeleted()) {
617 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
618 } elsif ($map->isnew()) {
619 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
625 $map->usr($new_patron->id);
627 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
629 my $stat = $session->request($method, $map)->gather(1);
630 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
633 return ($new_patron, undef);
638 __PACKAGE__->register_method(
639 method => "search_username",
640 api_name => "open-ils.actor.user.search.username",
643 sub search_username {
644 my($self, $client, $username) = @_;
645 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
647 "open-ils.storage.direct.actor.user.search.usrname.atomic",
655 __PACKAGE__->register_method(
656 method => "user_retrieve_by_barcode",
657 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
659 sub user_retrieve_by_barcode {
660 my($self, $client, $user_session, $barcode) = @_;
662 $logger->debug("Searching for user with barcode $barcode");
663 my ($user_obj, $evt) = $apputils->checkses($user_session);
666 my $session = OpenSRF::AppSession->create("open-ils.storage");
668 # find the card with the given barcode
669 my $creq = $session->request(
670 "open-ils.storage.direct.actor.card.search.barcode.atomic",
672 my $card = $creq->gather(1);
674 if(!$card || !$card->[0]) {
675 $session->disconnect();
676 return OpenILS::Event->new( 'USER_NOT_FOUND' );
680 my $user = flesh_user($card->usr(), $session);
681 $session->disconnect();
682 if(!$user) { return OpenILS::Event->new( 'USER_NOT_FOUND' ); }
689 __PACKAGE__->register_method(
690 method => "get_user_by_id",
691 api_name => "open-ils.actor.user.retrieve",);
694 my ($self, $client, $user_session, $id) = @_;
696 my $user_obj = $apputils->check_user_session( $user_session );
698 return $apputils->simple_scalar_request(
700 "open-ils.storage.direct.actor.user.retrieve",
706 __PACKAGE__->register_method(
707 method => "get_org_types",
708 api_name => "open-ils.actor.org_types.retrieve",);
712 my($self, $client) = @_;
714 return $org_types if $org_types;
716 $apputils->simple_scalar_request(
718 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
723 __PACKAGE__->register_method(
724 method => "get_user_profiles",
725 api_name => "open-ils.actor.user.profiles.retrieve",
729 sub get_user_profiles {
730 return $user_profiles if $user_profiles;
732 return $user_profiles =
733 $apputils->simple_scalar_request(
735 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
740 __PACKAGE__->register_method(
741 method => "get_user_ident_types",
742 api_name => "open-ils.actor.user.ident_types.retrieve",
745 sub get_user_ident_types {
746 return $ident_types if $ident_types;
747 return $ident_types =
748 $apputils->simple_scalar_request(
750 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
756 __PACKAGE__->register_method(
757 method => "get_org_unit",
758 api_name => "open-ils.actor.org_unit.retrieve",
763 my( $self, $client, $user_session, $org_id ) = @_;
765 if(defined($user_session) && !defined($org_id)) {
767 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
768 if(!defined($org_id)) {
769 $org_id = $user_obj->home_ou;
774 my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
776 "open-ils.storage.direct.actor.org_unit.retrieve",
785 __PACKAGE__->register_method(
786 method => "get_org_tree",
787 api_name => "open-ils.actor.org_tree.retrieve",
789 note => "Returns the entire org tree structure",
793 my( $self, $client) = @_;
796 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
798 # see if it's in the cache
799 #warn "Getting ORG Tree\n";
800 my $tree = $cache_client->get_cache('orgtree');
802 #warn "Found orgtree in cache. returning...\n";
806 my $orglist = $apputils->simple_scalar_request(
808 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
811 #warn "found org list\n";
814 $tree = $self->build_org_tree($orglist);
815 $cache_client->put_cache('orgtree', $tree);
821 # turns an org list into an org tree
824 my( $self, $orglist) = @_;
826 return $orglist unless (
827 ref($orglist) and @$orglist > 1 );
830 $a->ou_type <=> $b->ou_type ||
831 $a->name cmp $b->name } @$orglist;
833 for my $org (@list) {
835 next unless ($org and defined($org->parent_ou));
836 my ($parent) = grep { $_->id == $org->parent_ou } @list;
839 $parent->children([]) unless defined($parent->children);
840 push( @{$parent->children}, $org );
848 __PACKAGE__->register_method(
849 method => "get_org_descendants",
850 api_name => "open-ils.actor.org_tree.descendants.retrieve"
853 # depth is optional. org_unit is the id
854 sub get_org_descendants {
855 my( $self, $client, $org_unit, $depth ) = @_;
856 my $orglist = $apputils->simple_scalar_request(
858 "open-ils.storage.actor.org_unit.descendants.atomic",
860 return $self->build_org_tree($orglist);
864 __PACKAGE__->register_method(
865 method => "get_org_ancestors",
866 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
869 # depth is optional. org_unit is the id
870 sub get_org_ancestors {
871 my( $self, $client, $org_unit, $depth ) = @_;
872 my $orglist = $apputils->simple_scalar_request(
874 "open-ils.storage.actor.org_unit.ancestors.atomic",
876 return $self->build_org_tree($orglist);
880 __PACKAGE__->register_method(
881 method => "get_standings",
882 api_name => "open-ils.actor.standings.retrieve"
887 return $user_standings if $user_standings;
888 return $user_standings =
889 $apputils->simple_scalar_request(
891 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
896 __PACKAGE__->register_method(
897 method => "get_my_org_path",
898 api_name => "open-ils.actor.org_unit.full_path.retrieve"
901 sub get_my_org_path {
902 my( $self, $client, $user_session, $org_id ) = @_;
903 my $user_obj = $apputils->check_user_session($user_session);
904 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
906 return $apputils->simple_scalar_request(
908 "open-ils.storage.actor.org_unit.full_path.atomic",
913 __PACKAGE__->register_method(
914 method => "patron_adv_search",
915 api_name => "open-ils.actor.patron.search.advanced" );
917 sub patron_adv_search {
918 my( $self, $client, $staff_login, $search_hash ) = @_;
920 #warn "patron adv with $staff_login and search " .
921 #Dumper($search_hash) . "\n";
923 my $session = OpenSRF::AppSession->create("open-ils.storage");
924 my $req = $session->request(
925 "open-ils.storage.actor.user.crazy_search", $search_hash);
927 my $ans = $req->gather(1);
929 my %hash = map { ($_ =>1) } @$ans;
930 $ans = [ keys %hash ];
932 #warn "Returning @$ans\n";
934 $session->disconnect();
941 sub _verify_password {
942 my($user_session, $password) = @_;
943 my $user_obj = $apputils->check_user_session($user_session);
945 #grab the user with password
946 $user_obj = $apputils->simple_scalar_request(
948 "open-ils.storage.direct.actor.user.retrieve",
951 if($user_obj->passwd eq $password) {
959 __PACKAGE__->register_method(
960 method => "update_password",
961 api_name => "open-ils.actor.user.password.update");
963 __PACKAGE__->register_method(
964 method => "update_password",
965 api_name => "open-ils.actor.user.username.update");
967 __PACKAGE__->register_method(
968 method => "update_password",
969 api_name => "open-ils.actor.user.email.update");
971 sub update_password {
972 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
976 #warn "Updating user with method " .$self->api_name . "\n";
977 my $user_obj = $apputils->check_user_session($user_session);
979 if($self->api_name =~ /password/o) {
981 #make sure they know the current password
982 if(!_verify_password($user_session, md5_hex($current_password))) {
983 return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
986 $user_obj->passwd($new_value);
988 elsif($self->api_name =~ /username/o) {
989 my $users = search_username(undef, undef, $new_value);
990 if( $users and $users->[0] ) {
991 return OpenILS::Event->new('USERNAME_EXISTS');
993 $user_obj->usrname($new_value);
996 elsif($self->api_name =~ /email/o) {
997 #warn "Updating email to $new_value\n";
998 $user_obj->email($new_value);
1001 my $session = $apputils->start_db_session();
1003 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj);
1004 return $evt if $evt;
1006 $apputils->commit_db_session($session);
1008 if($user_obj) { return 1; }
1013 __PACKAGE__->register_method(
1014 method => "check_user_perms",
1015 api_name => "open-ils.actor.user.perm.check",
1016 notes => <<" NOTES");
1017 Takes a login session, user id, an org id, and an array of perm type strings. For each
1018 perm type, if the user does *not* have the given permission it is added
1019 to a list which is returned from the method. If all permissions
1020 are allowed, an empty list is returned
1021 if the logged in user does not match 'user_id', then the logged in user must
1022 have VIEW_PERMISSION priveleges.
1025 sub check_user_perms {
1026 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1028 my( $staff, $evt ) = $apputils->checkses($login_session);
1029 return $evt if $evt;
1031 if($staff->id ne $user_id) {
1032 if( my $evt = $apputils->check_perms(
1033 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1039 for my $perm (@$perm_types) {
1040 if($apputils->check_perms($user_id, $org_id, $perm)) {
1041 push @not_allowed, $perm;
1045 return \@not_allowed
1048 __PACKAGE__->register_method(
1049 method => "check_user_perms2",
1050 api_name => "open-ils.actor.user.perm.check.multi_org",
1052 Checks the permissions on a list of perms and orgs for a user
1053 @param authtoken The login session key
1054 @param user_id The id of the user to check
1055 @param orgs The array of org ids
1056 @param perms The array of permission names
1057 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1058 if the logged in user does not match 'user_id', then the logged in user must
1059 have VIEW_PERMISSION priveleges.
1062 sub check_user_perms2 {
1063 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1065 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1066 $authtoken, $user_id, 'VIEW_PERMISSION' );
1067 return $evt if $evt;
1070 for my $org (@$orgs) {
1071 for my $perm (@$perms) {
1072 if($apputils->check_perms($user_id, $org, $perm)) {
1073 push @not_allowed, [ $org, $perm ];
1078 return \@not_allowed
1082 __PACKAGE__->register_method(
1083 method => 'check_user_perms3',
1084 api_name => 'open-ils.actor.user.perm.highest_org',
1086 Returns the highest org unit id at which a user has a given permission
1087 If the requestor does not match the target user, the requestor must have
1088 'VIEW_PERMISSION' rights at the home org unit of the target user
1089 @param authtoken The login session key
1090 @param userid The id of the user in question
1091 @param perm The permission to check
1092 @return The org unit highest in the org tree within which the user has
1093 the requested permission
1096 sub check_user_perms3 {
1097 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1099 my( $staff, $target, $org, $evt );
1101 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1102 $authtoken, $userid, 'VIEW_PERMISSION' );
1103 return $evt if $evt;
1105 my $tree = $self->get_org_tree();
1106 return _find_highest_perm_org( $perm, $userid, $target->home_ou, $tree );
1110 sub _find_highest_perm_org {
1111 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1112 my $org = $apputils->find_org($org_tree, $start_org );
1116 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1118 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1124 __PACKAGE__->register_method(
1125 method => 'check_user_perms4',
1126 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1128 Returns the highest org unit id at which a user has a given permission
1129 If the requestor does not match the target user, the requestor must have
1130 'VIEW_PERMISSION' rights at the home org unit of the target user
1131 @param authtoken The login session key
1132 @param userid The id of the user in question
1133 @param perms An array of perm names to check
1134 @return An array of orgId's representing the org unit
1135 highest in the org tree within which the user has the requested permission
1136 The arrah of orgId's has matches the order of the perms array
1139 sub check_user_perms4 {
1140 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1142 my( $staff, $target, $org, $evt );
1144 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1145 $authtoken, $userid, 'VIEW_PERMISSION' );
1146 return $evt if $evt;
1149 return [] unless ref($perms);
1150 my $tree = $self->get_org_tree();
1152 for my $p (@$perms) {
1153 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1161 __PACKAGE__->register_method(
1162 method => "user_fines_summary",
1163 api_name => "open-ils.actor.user.fines.summary",
1164 notes => <<" NOTES");
1165 Returns a short summary of the users total open fines, excluding voided fines
1166 Params are login_session, user_id
1167 Returns a 'mous' object.
1170 sub user_fines_summary {
1171 my( $self, $client, $login_session, $user_id ) = @_;
1173 my $user_obj = $apputils->check_user_session($login_session);
1174 if($user_obj->id ne $user_id) {
1175 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1176 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1180 return $apputils->simple_scalar_request(
1182 "open-ils.storage.direct.money.open_user_summary.search.usr",
1190 __PACKAGE__->register_method(
1191 method => "user_transactions",
1192 api_name => "open-ils.actor.user.transactions",
1193 notes => <<" NOTES");
1194 Returns a list of open user transactions (mbts objects);
1195 Params are login_session, user_id
1196 Optional third parameter is the transactions type. defaults to all
1199 __PACKAGE__->register_method(
1200 method => "user_transactions",
1201 api_name => "open-ils.actor.user.transactions.have_charge",
1202 notes => <<" NOTES");
1203 Returns a list of all open user transactions (mbts objects) that have an initial charge
1204 Params are login_session, user_id
1205 Optional third parameter is the transactions type. defaults to all
1208 __PACKAGE__->register_method(
1209 method => "user_transactions",
1210 api_name => "open-ils.actor.user.transactions.have_balance",
1211 notes => <<" NOTES");
1212 Returns a list of all open user transactions (mbts objects) that have a balance
1213 Params are login_session, user_id
1214 Optional third parameter is the transactions type. defaults to all
1217 __PACKAGE__->register_method(
1218 method => "user_transactions",
1219 api_name => "open-ils.actor.user.transactions.fleshed",
1220 notes => <<" NOTES");
1221 Returns an object/hash of transaction, circ, title where transaction = an open
1222 user transactions (mbts objects), circ is the attached circluation, and title
1223 is the title the circ points to
1224 Params are login_session, user_id
1225 Optional third parameter is the transactions type. defaults to all
1228 __PACKAGE__->register_method(
1229 method => "user_transactions",
1230 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1231 notes => <<" NOTES");
1232 Returns an object/hash of transaction, circ, title where transaction = an open
1233 user transactions that has an initial charge (mbts objects), circ is the
1234 attached circluation, and title is the title the circ points to
1235 Params are login_session, user_id
1236 Optional third parameter is the transactions type. defaults to all
1239 __PACKAGE__->register_method(
1240 method => "user_transactions",
1241 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1242 notes => <<" NOTES");
1243 Returns an object/hash of transaction, circ, title where transaction = an open
1244 user transaction that has a balance (mbts objects), circ is the attached
1245 circluation, and title is the title the circ points to
1246 Params are login_session, user_id
1247 Optional third parameter is the transaction type. defaults to all
1250 __PACKAGE__->register_method(
1251 method => "user_transactions",
1252 api_name => "open-ils.actor.user.transactions.count",
1253 notes => <<" NOTES");
1254 Returns an object/hash of transaction, circ, title where transaction = an open
1255 user transactions (mbts objects), circ is the attached circluation, and title
1256 is the title the circ points to
1257 Params are login_session, user_id
1258 Optional third parameter is the transactions type. defaults to all
1261 __PACKAGE__->register_method(
1262 method => "user_transactions",
1263 api_name => "open-ils.actor.user.transactions.have_charge.count",
1264 notes => <<" NOTES");
1265 Returns an object/hash of transaction, circ, title where transaction = an open
1266 user transactions that has an initial charge (mbts objects), circ is the
1267 attached circluation, and title is the title the circ points to
1268 Params are login_session, user_id
1269 Optional third parameter is the transactions type. defaults to all
1272 __PACKAGE__->register_method(
1273 method => "user_transactions",
1274 api_name => "open-ils.actor.user.transactions.have_balance.count",
1275 notes => <<" NOTES");
1276 Returns an object/hash of transaction, circ, title where transaction = an open
1277 user transaction that has a balance (mbts objects), circ is the attached
1278 circluation, and title is the title the circ points to
1279 Params are login_session, user_id
1280 Optional third parameter is the transaction type. defaults to all
1283 __PACKAGE__->register_method(
1284 method => "user_transactions",
1285 api_name => "open-ils.actor.user.transactions.have_balance.total",
1286 notes => <<" NOTES");
1287 Returns an object/hash of transaction, circ, title where transaction = an open
1288 user transaction that has a balance (mbts objects), circ is the attached
1289 circluation, and title is the title the circ points to
1290 Params are login_session, user_id
1291 Optional third parameter is the transaction type. defaults to all
1296 sub user_transactions {
1297 my( $self, $client, $login_session, $user_id, $type ) = @_;
1299 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1300 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1301 return $evt if $evt;
1303 my $api = $self->api_name();
1307 if(defined($type)) { @xact = (xact_type => $type);
1309 } else { @xact = (); }
1311 if($api =~ /have_charge/o) {
1313 $trans = $apputils->simple_scalar_request(
1315 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1316 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1318 } elsif($api =~ /have_balance/o) {
1320 $trans = $apputils->simple_scalar_request(
1322 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1323 { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1327 $trans = $apputils->simple_scalar_request(
1329 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1330 { usr => $user_id, @xact });
1333 if($api =~ /total/o) {
1335 for my $t (@$trans) {
1336 $total += $t->balance_owed;
1339 $logger->debug("Total balance owed by user $user_id: $total");
1343 if($api =~ /count/o) { return scalar @$trans; }
1344 if($api !~ /fleshed/o) { return $trans; }
1346 #warn "API: $api\n";
1349 for my $t (@$trans) {
1351 #warn $t->id . "\n";
1354 if( $t->xact_type ne 'circulation' ) {
1355 push @resp, {transaction => $t};
1359 my $circ = $apputils->simple_scalar_request(
1361 "open-ils.storage.direct.action.circulation.retrieve",
1366 my $title = $apputils->simple_scalar_request(
1368 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1369 $circ->target_copy );
1373 my $u = OpenILS::Utils::ModsParser->new();
1374 $u->start_mods_batch($title->marc());
1375 my $mods = $u->finish_mods_batch();
1377 push @resp, {transaction => $t, circ => $circ, record => $mods };
1385 __PACKAGE__->register_method(
1386 method => "user_transaction_retrieve",
1387 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1389 notes => <<" NOTES");
1390 Returns a fleshedtransaction record
1392 __PACKAGE__->register_method(
1393 method => "user_transaction_retrieve",
1394 api_name => "open-ils.actor.user.transaction.retrieve",
1396 notes => <<" NOTES");
1397 Returns a transaction record
1399 sub user_transaction_retrieve {
1400 my( $self, $client, $login_session, $bill_id ) = @_;
1402 my $trans = $apputils->simple_scalar_request(
1404 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1408 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1409 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1410 return $evt if $evt;
1412 my $api = $self->api_name();
1413 if($api !~ /fleshed/o) { return $trans; }
1415 if( $trans->xact_type ne 'circulation' ) {
1416 $logger->debug("Returning non-circ transaction");
1417 return {transaction => $trans};
1420 my $circ = $apputils->simple_scalar_request(
1422 "open-ils.storage.direct.action.circulation.retrieve",
1425 return {transaction => $trans} unless $circ;
1426 $logger->debug("Found the circ transaction");
1428 my $title = $apputils->simple_scalar_request(
1430 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1431 $circ->target_copy );
1433 return {transaction => $trans, circ => $circ } unless $title;
1434 $logger->debug("Found the circ title");
1438 my $u = OpenILS::Utils::ModsParser->new();
1439 $u->start_mods_batch($title->marc());
1440 $mods = $u->finish_mods_batch();
1442 if ($title->id == -1) {
1443 my $copy = $apputils->simple_scalar_request(
1445 "open-ils.storage.direct.asset.copy.retrieve",
1446 $circ->target_copy );
1448 $mods = new Fieldmapper::metabib::virtual_record;
1450 $mods->title($copy->dummy_title);
1451 $mods->author($copy->dummy_author);
1455 $logger->debug("MODSized the circ title");
1457 return {transaction => $trans, circ => $circ, record => $mods };
1461 __PACKAGE__->register_method(
1462 method => "hold_request_count",
1463 api_name => "open-ils.actor.user.hold_requests.count",
1465 notes => <<" NOTES");
1466 Returns hold ready/total counts
1468 sub hold_request_count {
1469 my( $self, $client, $login_session, $userid ) = @_;
1471 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1472 $login_session, $userid, 'VIEW_HOLD' );
1473 return $evt if $evt;
1476 my $holds = $apputils->simple_scalar_request(
1478 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1480 fulfillment_time => {"=" => undef } }
1484 for my $h (@$holds) {
1485 next unless $h->capture_time;
1487 my $copy = $apputils->simple_scalar_request(
1489 "open-ils.storage.direct.asset.copy.retrieve",
1493 if ($copy->status == 8) {
1498 return { total => scalar(@$holds), ready => scalar(@ready) };
1502 __PACKAGE__->register_method(
1503 method => "checkedout_count",
1504 api_name => "open-ils.actor.user.checked_out.count",
1506 notes => <<" NOTES");
1507 Returns a transaction record
1509 sub checkedout_count {
1510 my( $self, $client, $login_session, $userid ) = @_;
1512 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1513 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1514 return $evt if $evt;
1517 my $circs = $apputils->simple_scalar_request(
1519 "open-ils.storage.direct.action.circulation.search_where.atomic",
1521 checkin_time => {"=" => undef } }
1524 my $parser = DateTime::Format::ISO8601->new;
1527 for my $c (@$circs) {
1528 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1529 my $due = $due_dt->epoch;
1536 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1539 __PACKAGE__->register_method(
1540 method => "user_transaction_history",
1541 api_name => "open-ils.actor.user.transactions.history",
1543 notes => <<" NOTES");
1544 Returns a list of billable transaction ids for a user, optionally by type
1546 sub user_transaction_history {
1547 my( $self, $client, $login_session, $user_id, $type ) = @_;
1549 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1550 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1551 return $evt if $evt;
1553 my $api = $self->api_name();
1556 @xact = (xact_type => $type) if(defined($type));
1558 my $trans = $apputils->simple_scalar_request(
1560 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1561 { usr => $user_id, @xact }, { order_by => 'xact_start DESC' });
1563 return [ map { $_->id } @$trans ];
1567 __PACKAGE__->register_method(
1568 method => "user_perms",
1569 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1571 notes => <<" NOTES");
1572 Returns a list of permissions
1575 my( $self, $client, $authtoken, $user ) = @_;
1577 my( $staff, $evt ) = $apputils->checkses($authtoken);
1578 return $evt if $evt;
1580 $user ||= $staff->id;
1582 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1586 return $apputils->simple_scalar_request(
1588 "open-ils.storage.permission.user_perms.atomic",
1592 __PACKAGE__->register_method(
1593 method => "retrieve_perms",
1594 api_name => "open-ils.actor.permissions.retrieve",
1595 notes => <<" NOTES");
1596 Returns a list of permissions
1598 sub retrieve_perms {
1599 my( $self, $client ) = @_;
1600 return $apputils->simple_scalar_request(
1602 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1605 __PACKAGE__->register_method(
1606 method => "retrieve_groups",
1607 api_name => "open-ils.actor.groups.retrieve",
1608 notes => <<" NOTES");
1609 Returns a list of user groupss
1611 sub retrieve_groups {
1612 my( $self, $client ) = @_;
1613 return $apputils->simple_scalar_request(
1615 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1618 __PACKAGE__->register_method(
1619 method => "retrieve_groups_tree",
1620 api_name => "open-ils.actor.groups.tree.retrieve",
1621 notes => <<" NOTES");
1622 Returns a list of user groups
1624 sub retrieve_groups_tree {
1625 my( $self, $client ) = @_;
1626 my $groups = $apputils->simple_scalar_request(
1628 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1629 return $self->build_group_tree($groups);
1633 # turns an org list into an org tree
1634 sub build_group_tree {
1636 my( $self, $grplist) = @_;
1638 return $grplist unless (
1639 ref($grplist) and @$grplist > 1 );
1641 my @list = sort { $a->name cmp $b->name } @$grplist;
1644 for my $grp (@list) {
1646 if ($grp and !defined($grp->parent)) {
1650 my ($parent) = grep { $_->id == $grp->parent} @list;
1652 $parent->children([]) unless defined($parent->children);
1653 push( @{$parent->children}, $grp );
1661 __PACKAGE__->register_method(
1662 method => "add_user_to_groups",
1663 api_name => "open-ils.actor.user.set_groups",
1664 notes => <<" NOTES");
1665 Adds a user to one or more permission groups
1668 sub add_user_to_groups {
1669 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1671 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1672 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1673 return $evt if $evt;
1675 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1676 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1677 return $evt if $evt;
1679 $apputils->simplereq(
1681 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1683 for my $group (@$groups) {
1684 my $link = Fieldmapper::permission::usr_grp_map->new;
1686 $link->usr($userid);
1688 my $id = $apputils->simplereq(
1690 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1696 __PACKAGE__->register_method(
1697 method => "get_user_perm_groups",
1698 api_name => "open-ils.actor.user.get_groups",
1699 notes => <<" NOTES");
1700 Retrieve a user's permission groups.
1704 sub get_user_perm_groups {
1705 my( $self, $client, $authtoken, $userid ) = @_;
1707 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1708 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
1709 return $evt if $evt;
1711 return $apputils->simplereq(
1713 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );