1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
5 $Data::Dumper::Indent = 0;
8 use Digest::MD5 qw(md5_hex);
10 use OpenSRF::EX qw(:try);
13 use OpenILS::Application::AppUtils;
15 use OpenILS::Utils::Fieldmapper;
16 use OpenILS::Utils::ModsParser;
17 use OpenSRF::Utils::Logger qw/$logger/;
18 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::Cache;
24 use DateTime::Format::ISO8601;
26 use OpenILS::Application::Actor::Container;
27 use OpenILS::Application::Actor::ClosedDates;
29 use OpenILS::Utils::Editor qw/:funcs/;
31 use OpenILS::Application::Actor::UserGroups;
33 OpenILS::Application::Actor::Container->initialize();
34 OpenILS::Application::Actor::UserGroups->initialize();
35 OpenILS::Application::Actor::ClosedDates->initialize();
38 my $apputils = "OpenILS::Application::AppUtils";
41 sub _d { warn "Patron:\n" . Dumper(shift()); }
46 my $set_user_settings;
49 __PACKAGE__->register_method(
50 method => "set_user_settings",
51 api_name => "open-ils.actor.patron.settings.update",
53 sub set_user_settings {
54 my( $self, $client, $user_session, $uid, $settings ) = @_;
56 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
58 my( $staff, $user, $evt ) =
59 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
63 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
65 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
67 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
69 return $apputils->simplereq(
71 'open-ils.storage.direct.actor.user_setting.batch.merge', @params );
77 __PACKAGE__->register_method(
78 method => "set_ou_settings",
79 api_name => "open-ils.actor.org_unit.settings.update",
82 my( $self, $client, $user_session, $ouid, $settings ) = @_;
84 my( $staff, $evt ) = $apputils->checkses( $user_session );
86 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
91 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
93 $_->[1]->{value} = JSON->perl2JSON($_->[1]->{value}) for @params;
95 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper(\@params));
97 return $apputils->simplereq(
99 'open-ils.storage.direct.actor.org_unit_setting.merge', @params );
103 my $fetch_user_settings;
104 my $fetch_ou_settings;
106 __PACKAGE__->register_method(
107 method => "user_settings",
108 api_name => "open-ils.actor.patron.settings.retrieve",
111 my( $self, $client, $user_session, $uid ) = @_;
113 my( $staff, $user, $evt ) =
114 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
117 $logger->debug("User " . $staff->id . " fetching user $uid\n");
118 my $s = $apputils->simplereq(
120 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
122 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
127 __PACKAGE__->register_method(
128 method => "ou_settings",
129 api_name => "open-ils.actor.org_unit.settings.retrieve",
132 my( $self, $client, $ouid ) = @_;
134 $logger->info("Fetching org unit settings for org $ouid");
136 my $s = $apputils->simplereq(
138 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
140 return { map { ( $_->name => JSON->JSON2perl($_->value) ) } @$s };
143 __PACKAGE__->register_method (
144 method => "ou_setting_delete",
145 api_name => 'open-ils.actor.org_setting.delete',
147 Deletes a specific org unit setting for a specific location
148 @param authtoken The login session key
149 @param orgid The org unit whose setting we're changing
150 @param setting The name of the setting to delete
151 @return True value on success.
155 sub ou_setting_delete {
156 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
157 my( $reqr, $evt) = $U->checkses($authtoken);
159 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
162 my $id = $U->storagereq(
163 'open-ils.storage.id_list.actor.org_unit_setting.search_where',
164 { name => $setting, org_unit => $orgid } );
166 $logger->debug("Retrieved setting $id in org unit setting delete");
168 my $s = $U->storagereq(
169 'open-ils.storage.direct.actor.org_unit_setting.delete', $id );
171 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
177 __PACKAGE__->register_method(
178 method => "update_patron",
179 api_name => "open-ils.actor.patron.update",);
182 my( $self, $client, $user_session, $patron ) = @_;
184 my $session = $apputils->start_db_session();
187 $logger->info("Creating new patron...") if $patron->isnew;
188 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
190 my( $user_obj, $evt ) = $U->checkses($user_session);
193 # XXX does this user have permission to add/create users. Granularity?
194 # $new_patron is the patron in progress. $patron is the original patron
195 # passed in with the method. new_patron will change as the components
196 # of patron are added/updated.
200 # unflesh the real items on the patron
201 $patron->card( $patron->card->id ) if(ref($patron->card));
202 $patron->billing_address( $patron->billing_address->id )
203 if(ref($patron->billing_address));
204 $patron->mailing_address( $patron->mailing_address->id )
205 if(ref($patron->mailing_address));
207 # create/update the patron first so we can use his id
208 if($patron->isnew()) {
209 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
211 } else { $new_patron = $patron; }
213 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
216 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
219 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
222 # re-update the patron if anything has happened to him during this process
223 if($new_patron->ischanged()) {
224 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
228 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
230 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
233 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
236 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
239 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
240 $apputils->commit_db_session($session);
242 #warn "Patron Update/Create complete\n";
243 return flesh_user($new_patron->id());
249 __PACKAGE__->register_method(
250 method => "user_retrieve_fleshed_by_id",
251 api_name => "open-ils.actor.user.fleshed.retrieve",);
253 sub user_retrieve_fleshed_by_id {
254 my( $self, $client, $user_session, $user_id ) = @_;
256 my( $requestor, $target, $evt ) = $apputils->
257 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
260 return flesh_user($user_id);
264 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
272 $session = OpenSRF::AppSession->create("open-ils.storage");
276 # grab the user with the given id
277 my $ureq = $session->request(
278 "open-ils.storage.direct.actor.user.retrieve", $id);
279 my $user = $ureq->gather(1);
281 if(!$user) { return undef; }
284 my $cards_req = $session->request(
285 "open-ils.storage.direct.actor.card.search.usr.atomic",
287 $user->cards( $cards_req->gather(1) );
289 for my $c(@{$user->cards}) {
290 if($c->id == $user->card || $c->id eq $user->card ) {
291 #warn "Setting my card to " . $c->id . "\n";
296 my $add_req = $session->request(
297 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
299 $user->addresses( $add_req->gather(1) );
301 if( @{$user->addresses} ) {
302 if( ! grep { $_->id eq $user->billing_address } @{$user->addresses} ) {
303 my $ba = $session->request(
304 'open-ils.storage.direct.actor.user_address.retrieve',
305 $user->billing_address)->gather(1);
306 push( @{$user->addresses}, $ba );
309 if( ! grep { $_->id eq $user->mailing_address } @{$user->addresses} ) {
310 my $ba = $session->request(
311 'open-ils.storage.direct.actor.user_address.retrieve',
312 $user->mailing_address)->gather(1);
313 push( @{$user->addresses}, $ba );
318 for my $c(@{$user->addresses}) {
319 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
320 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
323 my $stat_req = $session->request(
324 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
326 $user->stat_cat_entries($stat_req->gather(1));
328 my $standing_penalties_req = $session->request(
329 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
331 $user->standing_penalties($standing_penalties_req->gather(1));
333 if($kill) { $session->disconnect(); }
334 $user->clear_passwd();
340 # clone and clear stuff that would break the database
344 my $new_patron = $patron->clone;
346 # Using the Fieldmapper clone method
347 #my $new_patron = Fieldmapper::actor::user->new();
349 #my $fmap = $Fieldmapper::fieldmap;
350 #no strict; # shallow clone, may be useful in the fieldmapper
352 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
353 # $new_patron->$field( $patron->$field() );
358 $new_patron->clear_billing_address();
359 $new_patron->clear_mailing_address();
360 $new_patron->clear_addresses();
361 $new_patron->clear_card();
362 $new_patron->clear_cards();
363 $new_patron->clear_id();
364 $new_patron->clear_isnew();
365 $new_patron->clear_ischanged();
366 $new_patron->clear_isdeleted();
367 $new_patron->clear_stat_cat_entries();
368 $new_patron->clear_permissions();
369 $new_patron->clear_standing_penalties();
379 my $user_obj = shift;
381 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
382 return (undef, $evt) if $evt;
384 my $ex = $session->request(
385 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
387 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
390 $evt = _check_dup_ident($session, $patron);
391 return (undef, $evt) if $evt;
393 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
395 my $id = $session->request(
396 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
397 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
399 $logger->info("Successfully created new user [$id] in DB");
401 return ( $session->request(
402 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
407 my( $session, $patron, $user_obj, $noperm) = @_;
409 $logger->info("Updating patron ".$patron->id." in DB");
414 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
415 return (undef, $evt) if $evt;
418 $evt = _check_dup_ident($session, $patron);
419 return (undef, $evt) if $evt;
422 # update the password by itself to avoid the password protection magic
423 if( $patron->passwd ) {
424 my $s = $session->request(
425 'open-ils.storage.direct.actor.user.remote_update',
426 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
427 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
428 $patron->clear_passwd;
431 if(!$patron->ident_type) {
432 $patron->clear_ident_type;
433 $patron->clear_ident_value;
436 if(!$patron->ident_type2) {
437 $patron->clear_ident_type2;
438 $patron->clear_ident_value2;
441 my $stat = $session->request(
442 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
443 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
448 sub _check_dup_ident {
449 my( $session, $patron ) = @_;
451 return undef unless $patron->ident_value;
454 ident_type => $patron->ident_type,
455 ident_value => $patron->ident_value,
458 $logger->debug("patron update searching for dup ident values: " .
459 $patron->ident_type . ':' . $patron->ident_value);
461 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
463 my $dups = $session->request(
464 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
467 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
474 sub _add_update_addresses {
478 my $new_patron = shift;
482 my $current_id; # id of the address before creation
484 for my $address (@{$patron->addresses()}) {
486 next unless ref $address;
487 $current_id = $address->id();
489 if( $patron->billing_address() and
490 $patron->billing_address() == $current_id ) {
491 $logger->info("setting billing addr to $current_id");
492 $new_patron->billing_address($address->id());
493 $new_patron->ischanged(1);
496 if( $patron->mailing_address() and
497 $patron->mailing_address() == $current_id ) {
498 $new_patron->mailing_address($address->id());
499 $logger->info("setting mailing addr to $current_id");
500 $new_patron->ischanged(1);
504 if($address->isnew()) {
506 $address->usr($new_patron->id());
508 ($address, $evt) = _add_address($session,$address);
509 return (undef, $evt) if $evt;
511 # we need to get the new id
512 if( $patron->billing_address() and
513 $patron->billing_address() == $current_id ) {
514 $new_patron->billing_address($address->id());
515 $logger->info("setting billing addr to $current_id");
516 $new_patron->ischanged(1);
519 if( $patron->mailing_address() and
520 $patron->mailing_address() == $current_id ) {
521 $new_patron->mailing_address($address->id());
522 $logger->info("setting mailing addr to $current_id");
523 $new_patron->ischanged(1);
526 } elsif($address->ischanged() ) {
528 ($address, $evt) = _update_address($session, $address);
529 return (undef, $evt) if $evt;
531 } elsif($address->isdeleted() ) {
533 if( $address->id() == $new_patron->mailing_address() ) {
534 $new_patron->clear_mailing_address();
535 ($new_patron, $evt) = _update_patron($session, $new_patron);
536 return (undef, $evt) if $evt;
539 if( $address->id() == $new_patron->billing_address() ) {
540 $new_patron->clear_billing_address();
541 ($new_patron, $evt) = _update_patron($session, $new_patron);
542 return (undef, $evt) if $evt;
545 $evt = _delete_address($session, $address);
546 return (undef, $evt) if $evt;
550 return ( $new_patron, undef );
554 # adds an address to the db and returns the address with new id
556 my($session, $address) = @_;
557 $address->clear_id();
559 $logger->info("Creating new address at street ".$address->street1);
561 # put the address into the database
562 my $id = $session->request(
563 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
564 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
567 return ($address, undef);
571 sub _update_address {
572 my( $session, $address ) = @_;
574 $logger->info("Updating address ".$address->id." in the DB");
576 my $stat = $session->request(
577 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
579 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
580 return ($address, undef);
585 sub _add_update_cards {
589 my $new_patron = shift;
593 my $virtual_id; #id of the card before creation
594 for my $card (@{$patron->cards()}) {
596 $card->usr($new_patron->id());
598 if(ref($card) and $card->isnew()) {
600 $virtual_id = $card->id();
601 ( $card, $evt ) = _add_card($session,$card);
602 return (undef, $evt) if $evt;
604 #if(ref($patron->card)) { $patron->card($patron->card->id); }
605 if($patron->card() == $virtual_id) {
606 $new_patron->card($card->id());
607 $new_patron->ischanged(1);
610 } elsif( ref($card) and $card->ischanged() ) {
611 $evt = _update_card($session, $card);
612 return (undef, $evt) if $evt;
616 return ( $new_patron, undef );
620 # adds an card to the db and returns the card with new id
622 my( $session, $card ) = @_;
625 $logger->info("Adding new patron card ".$card->barcode);
627 my $id = $session->request(
628 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
629 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
630 $logger->info("Successfully created patron card $id");
633 return ( $card, undef );
637 # returns event on error. returns undef otherwise
639 my( $session, $card ) = @_;
640 $logger->info("Updating patron card ".$card->id);
642 my $stat = $session->request(
643 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
644 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
651 # returns event on error. returns undef otherwise
652 sub _delete_address {
653 my( $session, $address ) = @_;
655 $logger->info("Deleting address ".$address->id." from DB");
657 my $stat = $session->request(
658 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
660 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
666 sub _add_survey_responses {
667 my ($session, $patron, $new_patron) = @_;
669 $logger->info( "Updating survey responses for patron ".$new_patron->id );
671 my $responses = $patron->survey_responses;
675 $_->usr($new_patron->id) for (@$responses);
677 my $evt = $U->simplereq( "open-ils.circ",
678 "open-ils.circ.survey.submit.user_id", $responses );
680 return (undef, $evt) if defined($U->event_code($evt));
684 return ( $new_patron, undef );
688 sub _create_stat_maps {
690 my($session, $user_session, $patron, $new_patron) = @_;
692 my $maps = $patron->stat_cat_entries();
694 for my $map (@$maps) {
696 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
698 if ($map->isdeleted()) {
699 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
701 } elsif ($map->isnew()) {
702 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
707 $map->target_usr($new_patron->id);
710 $logger->info("Updating stat entry with method $method and map $map");
712 my $stat = $session->request($method, $map)->gather(1);
713 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
717 return ($new_patron, undef);
720 sub _create_perm_maps {
722 my($session, $user_session, $patron, $new_patron) = @_;
724 my $maps = $patron->permissions;
726 for my $map (@$maps) {
728 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
729 if ($map->isdeleted()) {
730 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
731 } elsif ($map->isnew()) {
732 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
737 $map->usr($new_patron->id);
739 #warn( "Updating permissions with method $method and session $user_session and map $map" );
740 $logger->info( "Updating permissions with method $method and map $map" );
742 my $stat = $session->request($method, $map)->gather(1);
743 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
747 return ($new_patron, undef);
751 sub _create_standing_penalties {
753 my($session, $user_session, $patron, $new_patron) = @_;
755 my $maps = $patron->standing_penalties;
758 for my $map (@$maps) {
760 if ($map->isdeleted()) {
761 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
762 } elsif ($map->isnew()) {
763 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
769 $map->usr($new_patron->id);
771 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
773 my $stat = $session->request($method, $map)->gather(1);
774 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
777 return ($new_patron, undef);
782 __PACKAGE__->register_method(
783 method => "search_username",
784 api_name => "open-ils.actor.user.search.username",
787 sub search_username {
788 my($self, $client, $username) = @_;
789 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
791 "open-ils.storage.direct.actor.user.search.usrname.atomic",
799 __PACKAGE__->register_method(
800 method => "user_retrieve_by_barcode",
801 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
803 sub user_retrieve_by_barcode {
804 my($self, $client, $user_session, $barcode) = @_;
806 $logger->debug("Searching for user with barcode $barcode");
807 my ($user_obj, $evt) = $apputils->checkses($user_session);
811 my $session = OpenSRF::AppSession->create("open-ils.storage");
813 # find the card with the given barcode
814 my $creq = $session->request(
815 "open-ils.storage.direct.actor.card.search.barcode.atomic",
817 my $card = $creq->gather(1);
819 if(!$card || !$card->[0]) {
820 $session->disconnect();
821 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
825 my $user = flesh_user($card->usr(), $session);
827 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
830 $session->disconnect();
831 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
838 __PACKAGE__->register_method(
839 method => "get_user_by_id",
840 api_name => "open-ils.actor.user.retrieve",);
843 my ($self, $client, $user_session, $id) = @_;
845 my $user_obj = $apputils->check_user_session( $user_session );
847 return $apputils->simple_scalar_request(
849 "open-ils.storage.direct.actor.user.retrieve",
855 __PACKAGE__->register_method(
856 method => "get_org_types",
857 api_name => "open-ils.actor.org_types.retrieve",);
861 my($self, $client) = @_;
863 return $org_types if $org_types;
865 $apputils->simple_scalar_request(
867 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
872 __PACKAGE__->register_method(
873 method => "get_user_profiles",
874 api_name => "open-ils.actor.user.profiles.retrieve",
878 sub get_user_profiles {
879 return $user_profiles if $user_profiles;
881 return $user_profiles =
882 $apputils->simple_scalar_request(
884 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
889 __PACKAGE__->register_method(
890 method => "get_user_ident_types",
891 api_name => "open-ils.actor.user.ident_types.retrieve",
894 sub get_user_ident_types {
895 return $ident_types if $ident_types;
896 return $ident_types =
897 $apputils->simple_scalar_request(
899 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
905 __PACKAGE__->register_method(
906 method => "get_org_unit",
907 api_name => "open-ils.actor.org_unit.retrieve",
911 my( $self, $client, $user_session, $org_id ) = @_;
912 my $e = new_editor(authtoken => $user_session);
914 return $e->event unless $e->checkauth;
915 $org_id = $e->requestor->ws_ou;
917 my $o = $e->retrieve_actor_org_unit($org_id)
922 __PACKAGE__->register_method(
923 method => "search_org_unit",
924 api_name => "open-ils.actor.org_unit_list.search",
927 sub search_org_unit {
929 my( $self, $client, $field, $value ) = @_;
931 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
933 "open-ils.storage.direct.actor.org_unit.search.$field.atomic",
942 __PACKAGE__->register_method(
943 method => "get_org_tree",
944 api_name => "open-ils.actor.org_tree.retrieve",
946 note => "Returns the entire org tree structure",
950 my( $self, $client) = @_;
953 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
955 # see if it's in the cache
956 #warn "Getting ORG Tree\n";
957 my $tree = $cache_client->get_cache('orgtree');
959 #warn "Found orgtree in cache. returning...\n";
963 my $orglist = $apputils->simple_scalar_request(
965 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
968 #warn "found org list\n";
971 $tree = $self->build_org_tree($orglist);
972 $cache_client->put_cache('orgtree', $tree);
978 # turns an org list into an org tree
981 my( $self, $orglist) = @_;
983 return $orglist unless (
984 ref($orglist) and @$orglist > 1 );
987 $a->ou_type <=> $b->ou_type ||
988 $a->name cmp $b->name } @$orglist;
990 for my $org (@list) {
992 next unless ($org and defined($org->parent_ou));
993 my ($parent) = grep { $_->id == $org->parent_ou } @list;
996 $parent->children([]) unless defined($parent->children);
997 push( @{$parent->children}, $org );
1005 __PACKAGE__->register_method(
1006 method => "get_org_descendants",
1007 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1010 # depth is optional. org_unit is the id
1011 sub get_org_descendants {
1012 my( $self, $client, $org_unit, $depth ) = @_;
1013 my $orglist = $apputils->simple_scalar_request(
1015 "open-ils.storage.actor.org_unit.descendants.atomic",
1016 $org_unit, $depth );
1017 return $self->build_org_tree($orglist);
1021 __PACKAGE__->register_method(
1022 method => "get_org_ancestors",
1023 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1026 # depth is optional. org_unit is the id
1027 sub get_org_ancestors {
1028 my( $self, $client, $org_unit, $depth ) = @_;
1029 my $orglist = $apputils->simple_scalar_request(
1031 "open-ils.storage.actor.org_unit.ancestors.atomic",
1032 $org_unit, $depth );
1033 return $self->build_org_tree($orglist);
1037 __PACKAGE__->register_method(
1038 method => "get_standings",
1039 api_name => "open-ils.actor.standings.retrieve"
1044 return $user_standings if $user_standings;
1045 return $user_standings =
1046 $apputils->simple_scalar_request(
1048 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
1053 __PACKAGE__->register_method(
1054 method => "get_my_org_path",
1055 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1058 sub get_my_org_path {
1059 my( $self, $client, $user_session, $org_id ) = @_;
1060 my $user_obj = $apputils->check_user_session($user_session);
1061 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
1063 return $apputils->simple_scalar_request(
1065 "open-ils.storage.actor.org_unit.full_path.atomic",
1070 __PACKAGE__->register_method(
1071 method => "patron_adv_search",
1072 api_name => "open-ils.actor.patron.search.advanced" );
1073 sub patron_adv_search {
1074 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort ) = @_;
1075 my $e = OpenILS::Utils::Editor->new(authtoken=>$auth);
1076 return $e->event unless $e->checkauth;
1077 return $e->event unless $e->allowed('VIEW_USER');
1079 "open-ils.storage.actor.user.crazy_search",
1080 $search_hash, $search_limit, $search_sort);
1085 sub _verify_password {
1086 my($user_session, $password) = @_;
1087 my $user_obj = $apputils->check_user_session($user_session);
1089 #grab the user with password
1090 $user_obj = $apputils->simple_scalar_request(
1092 "open-ils.storage.direct.actor.user.retrieve",
1095 if($user_obj->passwd eq $password) {
1103 __PACKAGE__->register_method(
1104 method => "update_password",
1105 api_name => "open-ils.actor.user.password.update");
1107 __PACKAGE__->register_method(
1108 method => "update_password",
1109 api_name => "open-ils.actor.user.username.update");
1111 __PACKAGE__->register_method(
1112 method => "update_password",
1113 api_name => "open-ils.actor.user.email.update");
1115 sub update_password {
1116 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1120 my $user_obj = $apputils->check_user_session($user_session);
1122 if($self->api_name =~ /password/o) {
1124 #make sure they know the current password
1125 if(!_verify_password($user_session, md5_hex($current_password))) {
1126 return OpenILS::Event->new('INCORRECT_PASSWORD');
1129 $logger->debug("update_password setting new password $new_value");
1130 $user_obj->passwd($new_value);
1132 } elsif($self->api_name =~ /username/o) {
1133 my $users = search_username(undef, undef, $new_value);
1134 if( $users and $users->[0] ) {
1135 return OpenILS::Event->new('USERNAME_EXISTS');
1137 $user_obj->usrname($new_value);
1139 } elsif($self->api_name =~ /email/o) {
1140 #warn "Updating email to $new_value\n";
1141 $user_obj->email($new_value);
1144 my $session = $apputils->start_db_session();
1146 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1147 return $evt if $evt;
1149 $apputils->commit_db_session($session);
1151 if($user_obj) { return 1; }
1156 __PACKAGE__->register_method(
1157 method => "check_user_perms",
1158 api_name => "open-ils.actor.user.perm.check",
1159 notes => <<" NOTES");
1160 Takes a login session, user id, an org id, and an array of perm type strings. For each
1161 perm type, if the user does *not* have the given permission it is added
1162 to a list which is returned from the method. If all permissions
1163 are allowed, an empty list is returned
1164 if the logged in user does not match 'user_id', then the logged in user must
1165 have VIEW_PERMISSION priveleges.
1168 sub check_user_perms {
1169 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1171 my( $staff, $evt ) = $apputils->checkses($login_session);
1172 return $evt if $evt;
1174 if($staff->id ne $user_id) {
1175 if( my $evt = $apputils->check_perms(
1176 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1182 for my $perm (@$perm_types) {
1183 if($apputils->check_perms($user_id, $org_id, $perm)) {
1184 push @not_allowed, $perm;
1188 return \@not_allowed
1191 __PACKAGE__->register_method(
1192 method => "check_user_perms2",
1193 api_name => "open-ils.actor.user.perm.check.multi_org",
1195 Checks the permissions on a list of perms and orgs for a user
1196 @param authtoken The login session key
1197 @param user_id The id of the user to check
1198 @param orgs The array of org ids
1199 @param perms The array of permission names
1200 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1201 if the logged in user does not match 'user_id', then the logged in user must
1202 have VIEW_PERMISSION priveleges.
1205 sub check_user_perms2 {
1206 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1208 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1209 $authtoken, $user_id, 'VIEW_PERMISSION' );
1210 return $evt if $evt;
1213 for my $org (@$orgs) {
1214 for my $perm (@$perms) {
1215 if($apputils->check_perms($user_id, $org, $perm)) {
1216 push @not_allowed, [ $org, $perm ];
1221 return \@not_allowed
1225 __PACKAGE__->register_method(
1226 method => 'check_user_perms3',
1227 api_name => 'open-ils.actor.user.perm.highest_org',
1229 Returns the highest org unit id at which a user has a given permission
1230 If the requestor does not match the target user, the requestor must have
1231 'VIEW_PERMISSION' rights at the home org unit of the target user
1232 @param authtoken The login session key
1233 @param userid The id of the user in question
1234 @param perm The permission to check
1235 @return The org unit highest in the org tree within which the user has
1236 the requested permission
1239 sub check_user_perms3 {
1240 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1242 my( $staff, $target, $org, $evt );
1244 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1245 $authtoken, $userid, 'VIEW_PERMISSION' );
1246 return $evt if $evt;
1248 my $tree = $self->get_org_tree();
1249 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1253 sub _find_highest_perm_org {
1254 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1255 my $org = $apputils->find_org($org_tree, $start_org );
1259 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1261 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1267 __PACKAGE__->register_method(
1268 method => 'check_user_perms4',
1269 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1271 Returns the highest org unit id at which a user has a given permission
1272 If the requestor does not match the target user, the requestor must have
1273 'VIEW_PERMISSION' rights at the home org unit of the target user
1274 @param authtoken The login session key
1275 @param userid The id of the user in question
1276 @param perms An array of perm names to check
1277 @return An array of orgId's representing the org unit
1278 highest in the org tree within which the user has the requested permission
1279 The arrah of orgId's has matches the order of the perms array
1282 sub check_user_perms4 {
1283 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1285 my( $staff, $target, $org, $evt );
1287 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1288 $authtoken, $userid, 'VIEW_PERMISSION' );
1289 return $evt if $evt;
1292 return [] unless ref($perms);
1293 my $tree = $self->get_org_tree();
1295 for my $p (@$perms) {
1296 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1304 __PACKAGE__->register_method(
1305 method => "user_fines_summary",
1306 api_name => "open-ils.actor.user.fines.summary",
1307 notes => <<" NOTES");
1308 Returns a short summary of the users total open fines, excluding voided fines
1309 Params are login_session, user_id
1310 Returns a 'mous' object.
1313 sub user_fines_summary {
1314 my( $self, $client, $login_session, $user_id ) = @_;
1316 my $user_obj = $apputils->check_user_session($login_session);
1317 if($user_obj->id ne $user_id) {
1318 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1319 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1323 return $apputils->simple_scalar_request(
1325 "open-ils.storage.direct.money.open_user_summary.search.usr",
1333 __PACKAGE__->register_method(
1334 method => "user_transactions",
1335 api_name => "open-ils.actor.user.transactions",
1336 notes => <<" NOTES");
1337 Returns a list of open user transactions (mbts objects);
1338 Params are login_session, user_id
1339 Optional third parameter is the transactions type. defaults to all
1342 __PACKAGE__->register_method(
1343 method => "user_transactions",
1344 api_name => "open-ils.actor.user.transactions.have_charge",
1345 notes => <<" NOTES");
1346 Returns a list of all open user transactions (mbts objects) that have an initial charge
1347 Params are login_session, user_id
1348 Optional third parameter is the transactions type. defaults to all
1351 __PACKAGE__->register_method(
1352 method => "user_transactions",
1353 api_name => "open-ils.actor.user.transactions.have_balance",
1354 notes => <<" NOTES");
1355 Returns a list of all open user transactions (mbts objects) that have a balance
1356 Params are login_session, user_id
1357 Optional third parameter is the transactions type. defaults to all
1360 __PACKAGE__->register_method(
1361 method => "user_transactions",
1362 api_name => "open-ils.actor.user.transactions.fleshed",
1363 notes => <<" NOTES");
1364 Returns an object/hash of transaction, circ, title where transaction = an open
1365 user transactions (mbts objects), circ is the attached circluation, and title
1366 is the title the circ points to
1367 Params are login_session, user_id
1368 Optional third parameter is the transactions type. defaults to all
1371 __PACKAGE__->register_method(
1372 method => "user_transactions",
1373 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1374 notes => <<" NOTES");
1375 Returns an object/hash of transaction, circ, title where transaction = an open
1376 user transactions that has an initial charge (mbts objects), circ is the
1377 attached circluation, and title is the title the circ points to
1378 Params are login_session, user_id
1379 Optional third parameter is the transactions type. defaults to all
1382 __PACKAGE__->register_method(
1383 method => "user_transactions",
1384 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1385 notes => <<" NOTES");
1386 Returns an object/hash of transaction, circ, title where transaction = an open
1387 user transaction that has a balance (mbts objects), circ is the attached
1388 circluation, and title is the title the circ points to
1389 Params are login_session, user_id
1390 Optional third parameter is the transaction type. defaults to all
1393 __PACKAGE__->register_method(
1394 method => "user_transactions",
1395 api_name => "open-ils.actor.user.transactions.count",
1396 notes => <<" NOTES");
1397 Returns an object/hash of transaction, circ, title where transaction = an open
1398 user transactions (mbts objects), circ is the attached circluation, and title
1399 is the title the circ points to
1400 Params are login_session, user_id
1401 Optional third parameter is the transactions type. defaults to all
1404 __PACKAGE__->register_method(
1405 method => "user_transactions",
1406 api_name => "open-ils.actor.user.transactions.have_charge.count",
1407 notes => <<" NOTES");
1408 Returns an object/hash of transaction, circ, title where transaction = an open
1409 user transactions that has an initial charge (mbts objects), circ is the
1410 attached circluation, and title is the title the circ points to
1411 Params are login_session, user_id
1412 Optional third parameter is the transactions type. defaults to all
1415 __PACKAGE__->register_method(
1416 method => "user_transactions",
1417 api_name => "open-ils.actor.user.transactions.have_balance.count",
1418 notes => <<" NOTES");
1419 Returns an object/hash of transaction, circ, title where transaction = an open
1420 user transaction that has a balance (mbts objects), circ is the attached
1421 circluation, and title is the title the circ points to
1422 Params are login_session, user_id
1423 Optional third parameter is the transaction type. defaults to all
1426 __PACKAGE__->register_method(
1427 method => "user_transactions",
1428 api_name => "open-ils.actor.user.transactions.have_balance.total",
1429 notes => <<" NOTES");
1430 Returns an object/hash of transaction, circ, title where transaction = an open
1431 user transaction that has a balance (mbts objects), circ is the attached
1432 circluation, and title is the title the circ points to
1433 Params are login_session, user_id
1434 Optional third parameter is the transaction type. defaults to all
1439 sub user_transactions {
1440 my( $self, $client, $login_session, $user_id, $type ) = @_;
1442 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1443 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1444 return $evt if $evt;
1446 my $api = $self->api_name();
1450 if(defined($type)) { @xact = (xact_type => $type);
1452 } else { @xact = (); }
1454 if($api =~ /have_charge/o) {
1456 $trans = $apputils->simple_scalar_request(
1458 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1459 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1461 } elsif($api =~ /have_balance/o) {
1463 $trans = $apputils->simple_scalar_request(
1465 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1466 { usr => $user_id, balance_owed => { "<>" => 0 }, @xact });
1470 $trans = $apputils->simple_scalar_request(
1472 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1473 { usr => $user_id, @xact });
1476 if($api =~ /total/o) {
1478 for my $t (@$trans) {
1479 $total += $t->balance_owed;
1482 $logger->debug("Total balance owed by user $user_id: $total");
1486 if($api =~ /count/o) { return scalar @$trans; }
1487 if($api !~ /fleshed/o) { return $trans; }
1490 for my $t (@$trans) {
1492 if( $t->xact_type ne 'circulation' ) {
1493 push @resp, {transaction => $t};
1497 my $circ = $apputils->simple_scalar_request(
1499 "open-ils.storage.direct.action.circulation.retrieve",
1504 my $title = $apputils->simple_scalar_request(
1506 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1507 $circ->target_copy );
1511 my $u = OpenILS::Utils::ModsParser->new();
1512 $u->start_mods_batch($title->marc());
1513 my $mods = $u->finish_mods_batch();
1515 push @resp, {transaction => $t, circ => $circ, record => $mods };
1523 __PACKAGE__->register_method(
1524 method => "user_transaction_retrieve",
1525 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1527 notes => <<" NOTES");
1528 Returns a fleshedtransaction record
1530 __PACKAGE__->register_method(
1531 method => "user_transaction_retrieve",
1532 api_name => "open-ils.actor.user.transaction.retrieve",
1534 notes => <<" NOTES");
1535 Returns a transaction record
1537 sub user_transaction_retrieve {
1538 my( $self, $client, $login_session, $bill_id ) = @_;
1540 my $trans = $apputils->simple_scalar_request(
1542 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1546 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1547 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1548 return $evt if $evt;
1550 my $api = $self->api_name();
1551 if($api !~ /fleshed/o) { return $trans; }
1553 if( $trans->xact_type ne 'circulation' ) {
1554 $logger->debug("Returning non-circ transaction");
1555 return {transaction => $trans};
1558 my $circ = $apputils->simple_scalar_request(
1560 "open-ils.storage.direct.action.circulation.retrieve",
1563 return {transaction => $trans} unless $circ;
1564 $logger->debug("Found the circ transaction");
1566 my $title = $apputils->simple_scalar_request(
1568 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1569 $circ->target_copy );
1571 return {transaction => $trans, circ => $circ } unless $title;
1572 $logger->debug("Found the circ title");
1576 my $u = OpenILS::Utils::ModsParser->new();
1577 $u->start_mods_batch($title->marc());
1578 $mods = $u->finish_mods_batch();
1580 if ($title->id == -1) {
1581 my $copy = $apputils->simple_scalar_request(
1583 "open-ils.storage.direct.asset.copy.retrieve",
1584 $circ->target_copy );
1586 $mods = new Fieldmapper::metabib::virtual_record;
1588 $mods->title($copy->dummy_title);
1589 $mods->author($copy->dummy_author);
1593 $logger->debug("MODSized the circ title");
1595 return {transaction => $trans, circ => $circ, record => $mods };
1599 __PACKAGE__->register_method(
1600 method => "hold_request_count",
1601 api_name => "open-ils.actor.user.hold_requests.count",
1603 notes => <<" NOTES");
1604 Returns hold ready/total counts
1606 sub hold_request_count {
1607 my( $self, $client, $login_session, $userid ) = @_;
1609 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1610 $login_session, $userid, 'VIEW_HOLD' );
1611 return $evt if $evt;
1614 my $holds = $apputils->simple_scalar_request(
1616 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1618 fulfillment_time => {"=" => undef } }
1622 for my $h (@$holds) {
1623 next unless $h->capture_time;
1625 my $copy = $apputils->simple_scalar_request(
1627 "open-ils.storage.direct.asset.copy.retrieve",
1631 if ($copy->status == 8) {
1636 return { total => scalar(@$holds), ready => scalar(@ready) };
1640 __PACKAGE__->register_method(
1641 method => "checkedout_count",
1642 api_name => "open-ils.actor.user.checked_out.count__",
1644 notes => <<" NOTES");
1645 Returns a transaction record
1649 sub checkedout_count {
1650 my( $self, $client, $login_session, $userid ) = @_;
1652 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1653 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1654 return $evt if $evt;
1656 my $circs = $apputils->simple_scalar_request(
1658 "open-ils.storage.direct.action.circulation.search_where.atomic",
1659 { usr => $userid, stop_fines => undef }
1660 #{ usr => $userid, checkin_time => {"=" => undef } }
1663 my $parser = DateTime::Format::ISO8601->new;
1666 for my $c (@$circs) {
1667 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1668 my $due = $due_dt->epoch;
1670 if ($due < DateTime->today->epoch) {
1675 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1679 __PACKAGE__->register_method(
1680 method => "checked_out",
1681 api_name => "open-ils.actor.user.checked_out",
1684 Returns a structure of circulations objects sorted by
1685 out, overdue, lost, claims_returned, long_overdue.
1686 A list of IDs are returned of each type.
1687 lost, long_overdue, and claims_returned circ will not
1688 be "finished" (there is an outstanding balance or some
1689 other pending action on the circ).
1691 The .count method also includes a 'total' field which
1692 sums all "open" circs
1696 __PACKAGE__->register_method(
1697 method => "checked_out",
1698 api_name => "open-ils.actor.user.checked_out.count",
1700 signature => q/@see open-ils.actor.user.checked_out/
1704 my( $self, $conn, $auth, $userid ) = @_;
1706 my $e = new_editor(authtoken=>$auth);
1707 return $e->event unless $e->checkauth;
1709 if( $userid ne $e->requestor->id ) {
1710 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1713 my $count = $self->api_name =~ /count/;
1714 return _checked_out( $count, $e, $userid );
1718 my( $iscount, $e, $userid ) = @_;
1720 my $circs = $e->search_action_circulation(
1721 { usr => $userid, stop_fines => undef });
1723 my $parser = DateTime::Format::ISO8601->new;
1725 # split the circs up into overdue and not-overdue circs
1727 for my $c (@$circs) {
1728 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1729 my $due = $due_dt->epoch;
1730 if ($due < DateTime->today->epoch) {
1731 push @overdue, $c->id;
1737 # grab all of the lost, claims-returned, and longoverdue circs
1738 my $open = $e->search_action_circulation(
1739 {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1741 my( @lost, @cr, @lo );
1742 for my $c (@$open) {
1743 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1744 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1745 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1751 total => @$circs + @lost + @cr + @lo,
1752 out => scalar(@out),
1753 overdue => scalar(@overdue),
1754 lost => scalar(@lost),
1755 claims_returned => scalar(@cr),
1756 long_overdue => scalar(@lo)
1762 overdue => \@overdue,
1764 claims_returned => \@cr,
1765 long_overdue => \@lo
1773 __PACKAGE__->register_method(
1774 method => "user_transaction_history",
1775 api_name => "open-ils.actor.user.transactions.history",
1777 notes => <<" NOTES");
1778 Returns a list of billable transaction ids for a user, optionally by type
1780 __PACKAGE__->register_method(
1781 method => "user_transaction_history",
1782 api_name => "open-ils.actor.user.transactions.history.have_charge",
1784 notes => <<" NOTES");
1785 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
1787 __PACKAGE__->register_method(
1788 method => "user_transaction_history",
1789 api_name => "open-ils.actor.user.transactions.history.have_balance",
1791 notes => <<" NOTES");
1792 Returns a list of billable transaction ids for a user that have a balance, optionally by type
1796 sub _user_transaction_history {
1797 my( $self, $client, $login_session, $user_id, $type ) = @_;
1799 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1800 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1801 return $evt if $evt;
1803 my $api = $self->api_name();
1808 @xact = (xact_type => $type) if(defined($type));
1809 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1810 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
1812 $logger->debug("searching for transaction history: @xact : @balance, @charge");
1814 my $trans = $apputils->simple_scalar_request(
1816 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1817 { usr => $user_id, @xact, @charge, @balance }, { order_by => 'xact_start DESC' });
1819 return [ map { $_->id } @$trans ];
1824 sub user_transaction_history {
1825 my( $self, $conn, $auth, $userid, $type ) = @_;
1826 my $e = new_editor(authtoken=>$auth);
1827 return $e->event unless $e->checkauth;
1828 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS');
1830 my $api = $self->api_name;
1831 my @xact = (xact_type => $type) if(defined($type));
1832 my @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
1833 my @charge = (last_billing_ts => { "!=" => undef }) if $api =~ /have_charge/;
1835 return $e->search_money_billable_transaction_summary(
1837 { usr => $userid, @xact, @charge, @balance },
1838 { order_by => 'xact_start DESC' }
1844 __PACKAGE__->register_method(
1845 method => "user_perms",
1846 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1848 notes => <<" NOTES");
1849 Returns a list of permissions
1852 my( $self, $client, $authtoken, $user ) = @_;
1854 my( $staff, $evt ) = $apputils->checkses($authtoken);
1855 return $evt if $evt;
1857 $user ||= $staff->id;
1859 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1863 return $apputils->simple_scalar_request(
1865 "open-ils.storage.permission.user_perms.atomic",
1869 __PACKAGE__->register_method(
1870 method => "retrieve_perms",
1871 api_name => "open-ils.actor.permissions.retrieve",
1872 notes => <<" NOTES");
1873 Returns a list of permissions
1875 sub retrieve_perms {
1876 my( $self, $client ) = @_;
1877 return $apputils->simple_scalar_request(
1879 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1882 __PACKAGE__->register_method(
1883 method => "retrieve_groups",
1884 api_name => "open-ils.actor.groups.retrieve",
1885 notes => <<" NOTES");
1886 Returns a list of user groupss
1888 sub retrieve_groups {
1889 my( $self, $client ) = @_;
1890 return $apputils->simple_scalar_request(
1892 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1895 __PACKAGE__->register_method(
1896 method => "retrieve_org_address",
1897 api_name => "open-ils.actor.org_unit.address.retrieve",
1898 notes => <<' NOTES');
1899 Returns an org_unit address by ID
1900 @param An org_address ID
1902 sub retrieve_org_address {
1903 my( $self, $client, $id ) = @_;
1904 return $apputils->simple_scalar_request(
1906 "open-ils.storage.direct.actor.org_address.retrieve",
1911 __PACKAGE__->register_method(
1912 method => "retrieve_groups_tree",
1913 api_name => "open-ils.actor.groups.tree.retrieve",
1914 notes => <<" NOTES");
1915 Returns a list of user groups
1917 sub retrieve_groups_tree {
1918 my( $self, $client ) = @_;
1919 my $groups = $apputils->simple_scalar_request(
1921 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1922 return $self->build_group_tree($groups);
1926 # turns an org list into an org tree
1927 sub build_group_tree {
1929 my( $self, $grplist) = @_;
1931 return $grplist unless (
1932 ref($grplist) and @$grplist > 1 );
1934 my @list = sort { $a->name cmp $b->name } @$grplist;
1937 for my $grp (@list) {
1939 if ($grp and !defined($grp->parent)) {
1943 my ($parent) = grep { $_->id == $grp->parent} @list;
1945 $parent->children([]) unless defined($parent->children);
1946 push( @{$parent->children}, $grp );
1954 __PACKAGE__->register_method(
1955 method => "add_user_to_groups",
1956 api_name => "open-ils.actor.user.set_groups",
1957 notes => <<" NOTES");
1958 Adds a user to one or more permission groups
1961 sub add_user_to_groups {
1962 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1964 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1965 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1966 return $evt if $evt;
1968 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1969 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1970 return $evt if $evt;
1972 $apputils->simplereq(
1974 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1976 for my $group (@$groups) {
1977 my $link = Fieldmapper::permission::usr_grp_map->new;
1979 $link->usr($userid);
1981 my $id = $apputils->simplereq(
1983 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1989 __PACKAGE__->register_method(
1990 method => "get_user_perm_groups",
1991 api_name => "open-ils.actor.user.get_groups",
1992 notes => <<" NOTES");
1993 Retrieve a user's permission groups.
1997 sub get_user_perm_groups {
1998 my( $self, $client, $authtoken, $userid ) = @_;
2000 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2001 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2002 return $evt if $evt;
2004 return $apputils->simplereq(
2006 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
2011 __PACKAGE__->register_method (
2012 method => 'register_workstation',
2013 api_name => 'open-ils.actor.workstation.register.override',
2014 signature => q/@see open-ils.actor.workstation.register/);
2016 __PACKAGE__->register_method (
2017 method => 'register_workstation',
2018 api_name => 'open-ils.actor.workstation.register',
2020 Registers a new workstion in the system
2021 @param authtoken The login session key
2022 @param name The name of the workstation id
2023 @param owner The org unit that owns this workstation
2024 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2025 if the name is already in use.
2028 sub _register_workstation {
2029 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2030 my( $requestor, $evt ) = $U->checkses($authtoken);
2031 return $evt if $evt;
2032 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2033 return $evt if $evt;
2035 my $ws = $U->storagereq(
2036 'open-ils.storage.direct.actor.workstation.search.name', $name );
2037 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2039 $ws = Fieldmapper::actor::workstation->new;
2040 $ws->owning_lib($owner);
2043 my $id = $U->storagereq(
2044 'open-ils.storage.direct.actor.workstation.create', $ws );
2045 return $U->DB_UPDATE_FAILED($ws) unless $id;
2051 sub register_workstation {
2052 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2054 my $e = OpenILS::Utils::Editor->new(authtoken=>$authtoken, xact=>1);
2055 return $e->event unless $e->checkauth;
2056 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2057 my $existing = $e->search_actor_workstation({name => $name});
2060 if( $self->api_name =~ /override/o ) {
2061 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2062 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2064 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2068 my $ws = Fieldmapper::actor::workstation->new;
2069 $ws->owning_lib($owner);
2071 $e->create_actor_workstation($ws) or return $e->event;
2073 return $ws->id; # note: editor sets the id on the new object for us
2077 __PACKAGE__->register_method (
2078 method => 'fetch_patron_note',
2079 api_name => 'open-ils.actor.note.retrieve.all',
2081 Returns a list of notes for a given user
2082 Requestor must have VIEW_USER permission if pub==false and
2083 @param authtoken The login session key
2084 @param args Hash of params including
2085 patronid : the patron's id
2086 pub : true if retrieving only public notes
2090 sub fetch_patron_note {
2091 my( $self, $conn, $authtoken, $args ) = @_;
2092 my $patronid = $$args{patronid};
2094 my($reqr, $evt) = $U->checkses($authtoken);
2097 ($patron, $evt) = $U->fetch_user($patronid);
2098 return $evt if $evt;
2101 if( $patronid ne $reqr->id ) {
2102 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2103 return $evt if $evt;
2105 return $U->storagereq(
2106 'open-ils.storage.direct.actor.usr_note.search_where.atomic',
2107 { usr => $patronid, pub => 't' } );
2110 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2111 return $evt if $evt;
2113 return $U->storagereq(
2114 'open-ils.storage.direct.actor.usr_note.search.usr.atomic', $patronid );
2117 __PACKAGE__->register_method (
2118 method => 'create_user_note',
2119 api_name => 'open-ils.actor.note.create',
2121 Creates a new note for the given user
2122 @param authtoken The login session key
2123 @param note The note object
2126 sub create_user_note {
2127 my( $self, $conn, $authtoken, $note ) = @_;
2128 my( $reqr, $patron, $evt ) =
2129 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2130 return $evt if $evt;
2131 $logger->activity("user ".$reqr->id." creating note for user ".$note->usr);
2133 $note->pub('f') unless $note->pub;
2134 $note->creator($reqr->id);
2135 my $id = $U->storagereq(
2136 'open-ils.storage.direct.actor.usr_note.create', $note );
2137 return $U->DB_UPDATE_FAILED($note) unless $id;
2142 __PACKAGE__->register_method (
2143 method => 'delete_user_note',
2144 api_name => 'open-ils.actor.note.delete',
2146 Deletes a note for the given user
2147 @param authtoken The login session key
2148 @param noteid The note id
2151 sub delete_user_note {
2152 my( $self, $conn, $authtoken, $noteid ) = @_;
2154 my $note = $U->storagereq(
2155 'open-ils.storage.direct.actor.usr_note.retrieve', $noteid);
2156 return OpenILS::Event->new('ACTOR_USER_NOTE_NOT_FOUND') unless $note;
2158 my( $reqr, $patron, $evt ) =
2159 $U->checkses_requestor($authtoken, $note->usr, 'UPDATE_USER');
2160 return $evt if $evt;
2161 $logger->activity("user ".$reqr->id." deleting note [$noteid] for user ".$note->usr);
2163 my $stat = $U->storagereq(
2164 'open-ils.storage.direct.actor.usr_note.delete', $noteid );
2165 return $U->DB_UPDATE_FAILED($note) unless defined $stat;
2171 __PACKAGE__->register_method (
2172 method => 'create_closed_date',
2173 api_name => 'open-ils.actor.org_unit.closed_date.create',
2175 Creates a new closing entry for the given org_unit
2176 @param authtoken The login session key
2177 @param note The closed_date object
2180 sub create_closed_date {
2181 my( $self, $conn, $authtoken, $cd ) = @_;
2183 my( $user, $evt ) = $U->checkses($authtoken);
2184 return $evt if $evt;
2186 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2187 return $evt if $evt;
2189 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2191 my $id = $U->storagereq(
2192 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2193 return $U->DB_UPDATE_FAILED($cd) unless $id;
2198 __PACKAGE__->register_method (
2199 method => 'delete_closed_date',
2200 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2202 Deletes a closing entry for the given org_unit
2203 @param authtoken The login session key
2204 @param noteid The close_date id
2207 sub delete_closed_date {
2208 my( $self, $conn, $authtoken, $cd ) = @_;
2210 my( $user, $evt ) = $U->checkses($authtoken);
2211 return $evt if $evt;
2214 ($cd_obj, $evt) = fetch_closed_date($cd);
2215 return $evt if $evt;
2217 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2218 return $evt if $evt;
2220 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2222 my $stat = $U->storagereq(
2223 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2224 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2229 __PACKAGE__->register_method(
2230 method => 'usrname_exists',
2231 api_name => 'open-ils.actor.username.exists',
2233 Returns 1 if the requested username exists, returns 0 otherwise
2237 sub usrname_exists {
2238 my( $self, $conn, $auth, $usrname ) = @_;
2239 my $e = new_editor(authtoken=>$auth);
2240 return $e->event unless $e->checkauth;
2241 my $a = $e->search_actor_user({usrname => $usrname}, {idlist=>1});
2242 return $$a[0] if $a and @$a;
2246 __PACKAGE__->register_method(
2247 method => 'barcode_exists',
2248 api_name => 'open-ils.actor.barcode.exists',
2250 Returns 1 if the requested barcode exists, returns 0 otherwise
2254 sub barcode_exists {
2255 my( $self, $conn, $auth, $barcode ) = @_;
2256 my $e = new_editor(authtoken=>$auth);
2257 return $e->event unless $e->checkauth;
2258 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2259 return $$a[0] if $a and @$a;
2264 __PACKAGE__->register_method(
2265 method => 'retrieve_net_levels',
2266 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2269 sub retrieve_net_levels {
2270 my( $self, $conn, $auth ) = @_;
2271 my $e = new_editor(authtoken=>$auth);
2272 return $e->event unless $e->checkauth;
2273 return $e->retrieve_all_config_net_access_level();