1 package OpenILS::Application::Actor;
2 use OpenILS::Application;
3 use base qw/OpenILS::Application/;
4 use strict; use warnings;
6 $Data::Dumper::Indent = 0;
9 use Digest::MD5 qw(md5_hex);
11 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::ModsParser;
18 use OpenSRF::Utils::Logger qw/$logger/;
19 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::SettingsClient;
22 use OpenSRF::Utils::Cache;
24 use OpenSRF::Utils::JSON;
26 use DateTime::Format::ISO8601;
27 use OpenILS::Const qw/:const/;
29 use OpenILS::Application::Actor::Container;
30 use OpenILS::Application::Actor::ClosedDates;
32 use OpenILS::Utils::CStoreEditor qw/:funcs/;
34 use OpenILS::Application::Actor::UserGroups;
36 OpenILS::Application::Actor::Container->initialize();
37 OpenILS::Application::Actor::UserGroups->initialize();
38 OpenILS::Application::Actor::ClosedDates->initialize();
41 my $apputils = "OpenILS::Application::AppUtils";
44 sub _d { warn "Patron:\n" . Dumper(shift()); }
49 my $set_user_settings;
52 __PACKAGE__->register_method(
53 method => "set_user_settings",
54 api_name => "open-ils.actor.patron.settings.update",
56 sub set_user_settings {
57 my( $self, $client, $user_session, $uid, $settings ) = @_;
59 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
61 my( $staff, $user, $evt ) =
62 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
66 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
68 $_->[1]->{value} = OpenSRF::Utils::JSON->perl2JSON($_->[1]->{value}) for @params;
70 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
72 my $ses = $U->start_db_session();
73 my $stat = $ses->request(
74 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
75 $U->commit_db_session($ses);
81 __PACKAGE__->register_method(
82 method => "set_ou_settings",
83 api_name => "open-ils.actor.org_unit.settings.update",
86 my( $self, $client, $auth, $org_id, $settings ) = @_;
88 my $e = new_editor(authtoken => $auth, xact => 1);
89 return $e->die_event unless $e->checkauth;
90 return $e->die_event unless $e->allowed('UPDATE_ORG_SETTING', $org_id);
92 for my $name (keys %$settings) {
93 my $val = $$settings{$name};
94 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
97 $val = OpenSRF::Utils::JSON->perl2JSON($val);
100 $e->update_actor_org_unit_setting($set) or return $e->die_event;
102 $set = Fieldmapper::actor::org_unit_setting->new;
103 $set->org_unit($org_id);
106 $e->create_actor_org_unit_setting($set) or return $e->die_event;
109 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
117 my $fetch_user_settings;
118 my $fetch_ou_settings;
120 __PACKAGE__->register_method(
121 method => "user_settings",
122 api_name => "open-ils.actor.patron.settings.retrieve",
125 my( $self, $client, $auth, $user_id, $setting ) = @_;
127 my $e = new_editor(authtoken => $auth);
128 return $e->event unless $e->checkauth;
130 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
131 if($e->requestor->id != $user_id) {
132 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
135 my $s = $e->search_actor_user_setting({usr => $user_id});
136 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
138 return $$settings{$setting} if $setting;
144 __PACKAGE__->register_method(
145 method => "ou_settings",
146 api_name => "open-ils.actor.org_unit.settings.retrieve",
149 my( $self, $client, $ouid ) = @_;
151 $logger->info("Fetching org unit settings for org $ouid");
153 my $s = $apputils->simplereq(
155 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
157 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
162 __PACKAGE__->register_method(
163 api_name => 'open-ils.actor.ou_setting.ancestor_default',
164 method => 'ou_ancestor_setting',
167 # ------------------------------------------------------------------
168 # Attempts to find the org setting value for a given org. if not
169 # found at the requested org, searches up the org tree until it
170 # finds a parent that has the requested setting.
171 # when found, returns { org => $id, value => $value }
172 # otherwise, returns NULL
173 # ------------------------------------------------------------------
174 sub ou_ancestor_setting {
175 my( $self, $client, $orgid, $name ) = @_;
176 return $U->ou_ancestor_setting($orgid, $name);
182 __PACKAGE__->register_method (
183 method => "ou_setting_delete",
184 api_name => 'open-ils.actor.org_setting.delete',
186 Deletes a specific org unit setting for a specific location
187 @param authtoken The login session key
188 @param orgid The org unit whose setting we're changing
189 @param setting The name of the setting to delete
190 @return True value on success.
194 sub ou_setting_delete {
195 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
196 my( $reqr, $evt) = $U->checkses($authtoken);
198 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
201 my $id = $U->cstorereq(
202 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
203 { name => $setting, org_unit => $orgid } );
205 $logger->debug("Retrieved setting $id in org unit setting delete");
207 my $s = $U->cstorereq(
208 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
210 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
224 __PACKAGE__->register_method(
225 method => "update_patron",
226 api_name => "open-ils.actor.patron.update",);
229 my( $self, $client, $user_session, $patron ) = @_;
231 my $session = $apputils->start_db_session();
235 $logger->info("Creating new patron...") if $patron->isnew;
236 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
238 my( $user_obj, $evt ) = $U->checkses($user_session);
241 $evt = check_group_perm($session, $user_obj, $patron);
245 # $new_patron is the patron in progress. $patron is the original patron
246 # passed in with the method. new_patron will change as the components
247 # of patron are added/updated.
251 # unflesh the real items on the patron
252 $patron->card( $patron->card->id ) if(ref($patron->card));
253 $patron->billing_address( $patron->billing_address->id )
254 if(ref($patron->billing_address));
255 $patron->mailing_address( $patron->mailing_address->id )
256 if(ref($patron->mailing_address));
258 # create/update the patron first so we can use his id
259 if($patron->isnew()) {
260 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
262 } else { $new_patron = $patron; }
264 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
267 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
270 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
273 # re-update the patron if anything has happened to him during this process
274 if($new_patron->ischanged()) {
275 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
279 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
282 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
285 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
288 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
291 if(!$patron->isnew) {
292 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
295 $apputils->commit_db_session($session);
296 my $fuser = flesh_user($new_patron->id());
299 # Log the new and old patron for investigation
300 $logger->info("$user_session updating patron object. orig patron object = ".
301 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
311 return new_flesh_user($id, [
314 "standing_penalties",
318 "stat_cat_entries" ] );
326 # clone and clear stuff that would break the database
330 my $new_patron = $patron->clone;
332 $new_patron->clear_billing_address();
333 $new_patron->clear_mailing_address();
334 $new_patron->clear_addresses();
335 $new_patron->clear_card();
336 $new_patron->clear_cards();
337 $new_patron->clear_id();
338 $new_patron->clear_isnew();
339 $new_patron->clear_ischanged();
340 $new_patron->clear_isdeleted();
341 $new_patron->clear_stat_cat_entries();
342 $new_patron->clear_permissions();
343 $new_patron->clear_standing_penalties();
353 my $user_obj = shift;
355 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
356 return (undef, $evt) if $evt;
358 my $ex = $session->request(
359 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
361 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
364 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
366 my $id = $session->request(
367 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
368 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
370 $logger->info("Successfully created new user [$id] in DB");
372 return ( $session->request(
373 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
377 sub check_group_perm {
378 my( $session, $requestor, $patron ) = @_;
381 # first let's see if the requestor has
382 # priveleges to update this user in any way
383 if( ! $patron->isnew ) {
384 my $p = $session->request(
385 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
387 # If we are the requestor (trying to update our own account)
388 # and we are not trying to change our profile, we're good
389 if( $p->id == $requestor->id and
390 $p->profile == $patron->profile ) {
395 $evt = group_perm_failed($session, $requestor, $p);
399 # They are allowed to edit this patron.. can they put the
400 # patron into the group requested?
401 $evt = group_perm_failed($session, $requestor, $patron);
407 sub group_perm_failed {
408 my( $session, $requestor, $patron ) = @_;
412 my $grpid = $patron->profile;
416 $logger->debug("user update looking for group perm for group $grpid");
417 $grp = $session->request(
418 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
419 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
421 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
423 $logger->info("user update checking perm $perm on user ".
424 $requestor->id." for update/create on user username=".$patron->usrname);
426 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
434 my( $session, $patron, $user_obj, $noperm) = @_;
436 $logger->info("Updating patron ".$patron->id." in DB");
441 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
442 return (undef, $evt) if $evt;
445 # update the password by itself to avoid the password protection magic
446 if( $patron->passwd ) {
447 my $s = $session->request(
448 'open-ils.storage.direct.actor.user.remote_update',
449 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
450 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
451 $patron->clear_passwd;
454 if(!$patron->ident_type) {
455 $patron->clear_ident_type;
456 $patron->clear_ident_value;
459 $evt = verify_last_xact($session, $patron);
460 return (undef, $evt) if $evt;
462 my $stat = $session->request(
463 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
464 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
469 sub verify_last_xact {
470 my( $session, $patron ) = @_;
471 return undef unless $patron->id and $patron->id > 0;
472 my $p = $session->request(
473 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
474 my $xact = $p->last_xact_id;
475 return undef unless $xact;
476 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
477 return OpenILS::Event->new('XACT_COLLISION')
478 if $xact != $patron->last_xact_id;
483 sub _check_dup_ident {
484 my( $session, $patron ) = @_;
486 return undef unless $patron->ident_value;
489 ident_type => $patron->ident_type,
490 ident_value => $patron->ident_value,
493 $logger->debug("patron update searching for dup ident values: " .
494 $patron->ident_type . ':' . $patron->ident_value);
496 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
498 my $dups = $session->request(
499 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
502 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
509 sub _add_update_addresses {
513 my $new_patron = shift;
517 my $current_id; # id of the address before creation
519 for my $address (@{$patron->addresses()}) {
521 next unless ref $address;
522 $current_id = $address->id();
524 if( $patron->billing_address() and
525 $patron->billing_address() == $current_id ) {
526 $logger->info("setting billing addr to $current_id");
527 $new_patron->billing_address($address->id());
528 $new_patron->ischanged(1);
531 if( $patron->mailing_address() and
532 $patron->mailing_address() == $current_id ) {
533 $new_patron->mailing_address($address->id());
534 $logger->info("setting mailing addr to $current_id");
535 $new_patron->ischanged(1);
539 if($address->isnew()) {
541 $address->usr($new_patron->id());
543 ($address, $evt) = _add_address($session,$address);
544 return (undef, $evt) if $evt;
546 # we need to get the new id
547 if( $patron->billing_address() and
548 $patron->billing_address() == $current_id ) {
549 $new_patron->billing_address($address->id());
550 $logger->info("setting billing addr to $current_id");
551 $new_patron->ischanged(1);
554 if( $patron->mailing_address() and
555 $patron->mailing_address() == $current_id ) {
556 $new_patron->mailing_address($address->id());
557 $logger->info("setting mailing addr to $current_id");
558 $new_patron->ischanged(1);
561 } elsif($address->ischanged() ) {
563 ($address, $evt) = _update_address($session, $address);
564 return (undef, $evt) if $evt;
566 } elsif($address->isdeleted() ) {
568 if( $address->id() == $new_patron->mailing_address() ) {
569 $new_patron->clear_mailing_address();
570 ($new_patron, $evt) = _update_patron($session, $new_patron);
571 return (undef, $evt) if $evt;
574 if( $address->id() == $new_patron->billing_address() ) {
575 $new_patron->clear_billing_address();
576 ($new_patron, $evt) = _update_patron($session, $new_patron);
577 return (undef, $evt) if $evt;
580 $evt = _delete_address($session, $address);
581 return (undef, $evt) if $evt;
585 return ( $new_patron, undef );
589 # adds an address to the db and returns the address with new id
591 my($session, $address) = @_;
592 $address->clear_id();
594 $logger->info("Creating new address at street ".$address->street1);
596 # put the address into the database
597 my $id = $session->request(
598 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
599 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
602 return ($address, undef);
606 sub _update_address {
607 my( $session, $address ) = @_;
609 $logger->info("Updating address ".$address->id." in the DB");
611 my $stat = $session->request(
612 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
614 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
615 return ($address, undef);
620 sub _add_update_cards {
624 my $new_patron = shift;
628 my $virtual_id; #id of the card before creation
629 for my $card (@{$patron->cards()}) {
631 $card->usr($new_patron->id());
633 if(ref($card) and $card->isnew()) {
635 $virtual_id = $card->id();
636 ( $card, $evt ) = _add_card($session,$card);
637 return (undef, $evt) if $evt;
639 #if(ref($patron->card)) { $patron->card($patron->card->id); }
640 if($patron->card() == $virtual_id) {
641 $new_patron->card($card->id());
642 $new_patron->ischanged(1);
645 } elsif( ref($card) and $card->ischanged() ) {
646 $evt = _update_card($session, $card);
647 return (undef, $evt) if $evt;
651 return ( $new_patron, undef );
655 # adds an card to the db and returns the card with new id
657 my( $session, $card ) = @_;
660 $logger->info("Adding new patron card ".$card->barcode);
662 my $id = $session->request(
663 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
664 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
665 $logger->info("Successfully created patron card $id");
668 return ( $card, undef );
672 # returns event on error. returns undef otherwise
674 my( $session, $card ) = @_;
675 $logger->info("Updating patron card ".$card->id);
677 my $stat = $session->request(
678 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
679 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
686 # returns event on error. returns undef otherwise
687 sub _delete_address {
688 my( $session, $address ) = @_;
690 $logger->info("Deleting address ".$address->id." from DB");
692 my $stat = $session->request(
693 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
695 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
701 sub _add_survey_responses {
702 my ($session, $patron, $new_patron) = @_;
704 $logger->info( "Updating survey responses for patron ".$new_patron->id );
706 my $responses = $patron->survey_responses;
710 $_->usr($new_patron->id) for (@$responses);
712 my $evt = $U->simplereq( "open-ils.circ",
713 "open-ils.circ.survey.submit.user_id", $responses );
715 return (undef, $evt) if defined($U->event_code($evt));
719 return ( $new_patron, undef );
723 sub _create_stat_maps {
725 my($session, $user_session, $patron, $new_patron) = @_;
727 my $maps = $patron->stat_cat_entries();
729 for my $map (@$maps) {
731 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
733 if ($map->isdeleted()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
736 } elsif ($map->isnew()) {
737 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
742 $map->target_usr($new_patron->id);
745 $logger->info("Updating stat entry with method $method and map $map");
747 my $stat = $session->request($method, $map)->gather(1);
748 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
752 return ($new_patron, undef);
755 sub _create_perm_maps {
757 my($session, $user_session, $patron, $new_patron) = @_;
759 my $maps = $patron->permissions;
761 for my $map (@$maps) {
763 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
764 if ($map->isdeleted()) {
765 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
766 } elsif ($map->isnew()) {
767 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
772 $map->usr($new_patron->id);
774 #warn( "Updating permissions with method $method and session $user_session and map $map" );
775 $logger->info( "Updating permissions with method $method and map $map" );
777 my $stat = $session->request($method, $map)->gather(1);
778 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
782 return ($new_patron, undef);
786 __PACKAGE__->register_method(
787 method => "set_user_work_ous",
788 api_name => "open-ils.actor.user.work_ous.update",
791 sub set_user_work_ous {
797 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
800 my $session = $apputils->start_db_session();
802 for my $map (@$maps) {
804 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
805 if ($map->isdeleted()) {
806 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
807 } elsif ($map->isnew()) {
808 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
812 #warn( "Updating permissions with method $method and session $ses and map $map" );
813 $logger->info( "Updating work_ou map with method $method and map $map" );
815 my $stat = $session->request($method, $map)->gather(1);
816 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
820 $apputils->commit_db_session($session);
822 return scalar(@$maps);
826 __PACKAGE__->register_method(
827 method => "set_user_perms",
828 api_name => "open-ils.actor.user.permissions.update",
837 my $session = $apputils->start_db_session();
839 my( $user_obj, $evt ) = $U->checkses($ses);
842 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
845 $all = 1 if ($U->is_true($user_obj->super_user()));
846 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
848 for my $map (@$maps) {
850 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
851 if ($map->isdeleted()) {
852 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
853 } elsif ($map->isnew()) {
854 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
858 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
859 #warn( "Updating permissions with method $method and session $ses and map $map" );
860 $logger->info( "Updating permissions with method $method and map $map" );
862 my $stat = $session->request($method, $map)->gather(1);
863 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
867 $apputils->commit_db_session($session);
869 return scalar(@$maps);
873 sub _create_standing_penalties {
875 my($session, $user_session, $patron, $new_patron) = @_;
877 my $maps = $patron->standing_penalties;
880 for my $map (@$maps) {
882 if ($map->isdeleted()) {
883 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
884 } elsif ($map->isnew()) {
885 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
891 $map->usr($new_patron->id);
893 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
895 my $stat = $session->request($method, $map)->gather(1);
896 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
899 return ($new_patron, undef);
904 __PACKAGE__->register_method(
905 method => "search_username",
906 api_name => "open-ils.actor.user.search.username",
909 sub search_username {
910 my($self, $client, $username) = @_;
911 return new_editor()->search_actor_user({usrname=>$username});
917 __PACKAGE__->register_method(
918 method => "user_retrieve_by_barcode",
920 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
922 sub user_retrieve_by_barcode {
923 my($self, $client, $user_session, $barcode) = @_;
925 $logger->debug("Searching for user with barcode $barcode");
926 my ($user_obj, $evt) = $apputils->checkses($user_session);
929 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
931 "open-ils.cstore.direct.actor.card.search.atomic",
932 { barcode => $barcode }
935 if(!$card || !$card->[0]) {
936 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
940 my $user = flesh_user($card->usr());
942 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
945 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
952 __PACKAGE__->register_method(
953 method => "get_user_by_id",
954 api_name => "open-ils.actor.user.retrieve",);
957 my ($self, $client, $auth, $id) = @_;
958 my $e = new_editor(authtoken=>$auth);
959 return $e->event unless $e->checkauth;
960 my $user = $e->retrieve_actor_user($id)
962 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
968 __PACKAGE__->register_method(
969 method => "get_org_types",
970 api_name => "open-ils.actor.org_types.retrieve",);
973 return $U->get_org_types();
978 __PACKAGE__->register_method(
979 method => "get_user_ident_types",
980 api_name => "open-ils.actor.user.ident_types.retrieve",
983 sub get_user_ident_types {
984 return $ident_types if $ident_types;
985 return $ident_types =
986 new_editor()->retrieve_all_config_identification_type();
992 __PACKAGE__->register_method(
993 method => "get_org_unit",
994 api_name => "open-ils.actor.org_unit.retrieve",
998 my( $self, $client, $user_session, $org_id ) = @_;
999 my $e = new_editor(authtoken => $user_session);
1001 return $e->event unless $e->checkauth;
1002 $org_id = $e->requestor->ws_ou;
1004 my $o = $e->retrieve_actor_org_unit($org_id)
1005 or return $e->event;
1009 __PACKAGE__->register_method(
1010 method => "search_org_unit",
1011 api_name => "open-ils.actor.org_unit_list.search",
1014 sub search_org_unit {
1016 my( $self, $client, $field, $value ) = @_;
1018 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1020 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1021 { $field => $value } );
1027 # build the org tree
1029 __PACKAGE__->register_method(
1030 method => "get_org_tree",
1031 api_name => "open-ils.actor.org_tree.retrieve",
1033 note => "Returns the entire org tree structure",
1039 return $U->get_org_tree($client->session->session_locale);
1043 __PACKAGE__->register_method(
1044 method => "get_org_descendants",
1045 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1048 # depth is optional. org_unit is the id
1049 sub get_org_descendants {
1050 my( $self, $client, $org_unit, $depth ) = @_;
1052 if(ref $org_unit eq 'ARRAY') {
1055 for my $i (0..scalar(@$org_unit)-1) {
1056 my $list = $U->simple_scalar_request(
1058 "open-ils.storage.actor.org_unit.descendants.atomic",
1059 $org_unit->[$i], $depth->[$i] );
1060 push(@trees, $U->build_org_tree($list));
1065 my $orglist = $apputils->simple_scalar_request(
1067 "open-ils.storage.actor.org_unit.descendants.atomic",
1068 $org_unit, $depth );
1069 return $U->build_org_tree($orglist);
1074 __PACKAGE__->register_method(
1075 method => "get_org_ancestors",
1076 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1079 # depth is optional. org_unit is the id
1080 sub get_org_ancestors {
1081 my( $self, $client, $org_unit, $depth ) = @_;
1082 my $orglist = $apputils->simple_scalar_request(
1084 "open-ils.storage.actor.org_unit.ancestors.atomic",
1085 $org_unit, $depth );
1086 return $U->build_org_tree($orglist);
1090 __PACKAGE__->register_method(
1091 method => "get_standings",
1092 api_name => "open-ils.actor.standings.retrieve"
1097 return $user_standings if $user_standings;
1098 return $user_standings =
1099 $apputils->simple_scalar_request(
1101 "open-ils.cstore.direct.config.standing.search.atomic",
1102 { id => { "!=" => undef } }
1108 __PACKAGE__->register_method(
1109 method => "get_my_org_path",
1110 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1113 sub get_my_org_path {
1114 my( $self, $client, $auth, $org_id ) = @_;
1115 my $e = new_editor(authtoken=>$auth);
1116 return $e->event unless $e->checkauth;
1117 $org_id = $e->requestor->ws_ou unless defined $org_id;
1119 return $apputils->simple_scalar_request(
1121 "open-ils.storage.actor.org_unit.full_path.atomic",
1126 __PACKAGE__->register_method(
1127 method => "patron_adv_search",
1128 api_name => "open-ils.actor.patron.search.advanced" );
1129 sub patron_adv_search {
1130 my( $self, $client, $auth, $search_hash,
1131 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1133 my $e = new_editor(authtoken=>$auth);
1134 return $e->event unless $e->checkauth;
1135 return $e->event unless $e->allowed('VIEW_USER');
1136 return $U->storagereq(
1137 "open-ils.storage.actor.user.crazy_search", $search_hash,
1138 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1142 __PACKAGE__->register_method(
1143 method => "update_passwd",
1145 api_name => "open-ils.actor.user.password.update");
1147 __PACKAGE__->register_method(
1148 method => "update_passwd",
1149 api_name => "open-ils.actor.user.username.update");
1151 __PACKAGE__->register_method(
1152 method => "update_passwd",
1153 api_name => "open-ils.actor.user.email.update");
1156 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1157 my $e = new_editor(xact=>1, authtoken=>$auth);
1158 return $e->die_event unless $e->checkauth;
1160 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1161 or return $e->die_event;
1162 my $api = $self->api_name;
1164 if( $api =~ /password/o ) {
1166 # make sure the original password matches the in-database password
1167 return OpenILS::Event->new('INCORRECT_PASSWORD')
1168 if md5_hex($orig_pw) ne $db_user->passwd;
1169 $db_user->passwd($new_val);
1173 # if we don't clear the password, the user will be updated with
1174 # a hashed version of the hashed version of their password
1175 $db_user->clear_passwd;
1177 if( $api =~ /username/o ) {
1179 # make sure no one else has this username
1180 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1181 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1182 $db_user->usrname($new_val);
1184 } elsif( $api =~ /email/o ) {
1185 $db_user->email($new_val);
1189 $e->update_actor_user($db_user) or return $e->die_event;
1197 __PACKAGE__->register_method(
1198 method => "check_user_perms",
1199 api_name => "open-ils.actor.user.perm.check",
1200 notes => <<" NOTES");
1201 Takes a login session, user id, an org id, and an array of perm type strings. For each
1202 perm type, if the user does *not* have the given permission it is added
1203 to a list which is returned from the method. If all permissions
1204 are allowed, an empty list is returned
1205 if the logged in user does not match 'user_id', then the logged in user must
1206 have VIEW_PERMISSION priveleges.
1209 sub check_user_perms {
1210 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1212 my( $staff, $evt ) = $apputils->checkses($login_session);
1213 return $evt if $evt;
1215 if($staff->id ne $user_id) {
1216 if( $evt = $apputils->check_perms(
1217 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1223 for my $perm (@$perm_types) {
1224 if($apputils->check_perms($user_id, $org_id, $perm)) {
1225 push @not_allowed, $perm;
1229 return \@not_allowed
1232 __PACKAGE__->register_method(
1233 method => "check_user_perms2",
1234 api_name => "open-ils.actor.user.perm.check.multi_org",
1236 Checks the permissions on a list of perms and orgs for a user
1237 @param authtoken The login session key
1238 @param user_id The id of the user to check
1239 @param orgs The array of org ids
1240 @param perms The array of permission names
1241 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1242 if the logged in user does not match 'user_id', then the logged in user must
1243 have VIEW_PERMISSION priveleges.
1246 sub check_user_perms2 {
1247 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1249 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1250 $authtoken, $user_id, 'VIEW_PERMISSION' );
1251 return $evt if $evt;
1254 for my $org (@$orgs) {
1255 for my $perm (@$perms) {
1256 if($apputils->check_perms($user_id, $org, $perm)) {
1257 push @not_allowed, [ $org, $perm ];
1262 return \@not_allowed
1266 __PACKAGE__->register_method(
1267 method => 'check_user_perms3',
1268 api_name => 'open-ils.actor.user.perm.highest_org',
1270 Returns the highest org unit id at which a user has a given permission
1271 If the requestor does not match the target user, the requestor must have
1272 'VIEW_PERMISSION' rights at the home org unit of the target user
1273 @param authtoken The login session key
1274 @param userid The id of the user in question
1275 @param perm The permission to check
1276 @return The org unit highest in the org tree within which the user has
1277 the requested permission
1280 sub check_user_perms3 {
1281 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1283 my( $staff, $target, $org, $evt );
1285 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1286 $authtoken, $userid, 'VIEW_PERMISSION' );
1287 return $evt if $evt;
1289 my $tree = $U->get_org_tree();
1290 return $U->find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1294 __PACKAGE__->register_method(
1295 method => 'check_user_work_perms',
1296 api_name => 'open-ils.actor.user.work_perm.highest_org_set',
1300 Returns a set of org units which represent the highest orgs in
1301 the org tree where the user has the requested permission. The
1302 purpose of this method is to return the smallest set of org units
1303 which represent the full expanse of the user's ability to perform
1304 the requested action. The user whose perms this method should
1305 check is implied by the authtoken. /,
1307 {desc => 'authtoken', type => 'string'},
1308 {desc => 'permission name', type => 'string'},
1309 {desc => 'options hash, including "descendants", which will include all child orgs of the found perm orgs', type => 'hash'}
1311 return => {desc => 'An array of org IDs'}
1315 __PACKAGE__->register_method(
1316 method => 'check_user_work_perms',
1317 api_name => 'open-ils.actor.user.work_perm.org_tree_list',
1320 @see open-ils.actor.user.work_perm.highest_org_set
1321 Returns a list of org trees. The root of each tree
1322 is the highest org in the organization hierarchy where the user has the
1323 requested permission. Below each tree root is its full tree of descendants.
1327 __PACKAGE__->register_method(
1328 method => 'check_user_work_perms',
1329 api_name => 'open-ils.actor.user.work_perm.org_unit_list',
1332 @see open-ils.actor.user.work_perm.highest_org_set
1333 Returns a list of list of all of the org_units where the user
1334 has the requested permission. The first item in each list
1335 is the highest permission org for that section of the
1336 org tree. The remaining items in each sub-list are the
1337 descendants of that org.
1342 __PACKAGE__->register_method(
1343 method => 'check_user_work_perms',
1344 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1347 @see open-ils.actor.user.work_perm.highest_org_set
1348 Returns a list of lists of all of the org_unit IDs where the user
1349 has the requested permission. The first item in each list
1350 is the highest permission org for that section of the
1351 org tree. The remaining items in each sub-list are the
1352 descendants of that org.
1356 __PACKAGE__->register_method(
1357 method => 'check_user_work_perms_batch',
1358 api_name => 'open-ils.actor.user.work_perm.highest_org_set.batch',
1361 __PACKAGE__->register_method(
1362 method => 'check_user_work_perms_batch',
1363 api_name => 'open-ils.actor.user.work_perm.org_tree_list.batch',
1366 __PACKAGE__->register_method(
1367 method => 'check_user_work_perms_batch',
1368 api_name => 'open-ils.actor.user.work_perm.org_unit_list.batch',
1371 __PACKAGE__->register_method(
1372 method => 'check_user_work_perms_batch',
1373 api_name => 'open-ils.actor.user.work_perm.org_id_list.batch',
1378 sub check_user_work_perms {
1379 my($self, $conn, $auth, $perm, $options) = @_;
1380 my $e = new_editor(authtoken=>$auth);
1381 return $e->event unless $e->checkauth;
1382 return check_user_work_perms_impl($self, $conn, $e, $perm, $options);
1385 sub check_user_work_perms_batch {
1386 my($self, $conn, $auth, $perm_list, $options) = @_;
1387 my $e = new_editor(authtoken=>$auth);
1388 return $e->event unless $e->checkauth;
1390 $map->{$_} = check_user_work_perms_impl($self, $conn, $e, $_, $options) for @$perm_list;
1394 sub check_user_work_perms_impl {
1395 my($self, $conn, $e, $perm, $options) = @_;
1396 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1398 return $orglist if $self->api_name =~ /highest_org_set/;
1400 # build a list of org trees
1401 return get_org_descendants($self, $conn, $orglist)
1402 if $self->api_name =~ /org_tree_list/;
1405 for my $orgid (@$orglist) {
1406 my @sublist = grep {$_ ne $orgid} @{$U->get_org_descendants($orgid)};
1407 unshift @sublist, $orgid; # make sure it's at the front of the list
1408 if($self->api_name =~ /org_id_list/) {
1409 push(@list, @sublist);
1411 push(@list, @{$e->batch_retrieve_actor_org_unit(\@sublist)});
1419 __PACKAGE__->register_method(
1420 method => 'check_user_perms4',
1421 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1423 Returns the highest org unit id at which a user has a given permission
1424 If the requestor does not match the target user, the requestor must have
1425 'VIEW_PERMISSION' rights at the home org unit of the target user
1426 @param authtoken The login session key
1427 @param userid The id of the user in question
1428 @param perms An array of perm names to check
1429 @return An array of orgId's representing the org unit
1430 highest in the org tree within which the user has the requested permission
1431 The arrah of orgId's has matches the order of the perms array
1434 sub check_user_perms4 {
1435 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1437 my( $staff, $target, $org, $evt );
1439 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1440 $authtoken, $userid, 'VIEW_PERMISSION' );
1441 return $evt if $evt;
1444 return [] unless ref($perms);
1445 my $tree = $U->get_org_tree();
1447 for my $p (@$perms) {
1448 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1456 __PACKAGE__->register_method(
1457 method => "user_fines_summary",
1458 api_name => "open-ils.actor.user.fines.summary",
1460 notes => <<" NOTES");
1461 Returns a short summary of the users total open fines, excluding voided fines
1462 Params are login_session, user_id
1463 Returns a 'mous' object.
1466 sub user_fines_summary {
1467 my( $self, $client, $auth, $user_id ) = @_;
1468 my $e = new_editor(authtoken=>$auth);
1469 return $e->event unless $e->checkauth;
1470 my $user = $e->retrieve_actor_user($user_id)
1471 or return $e->event;
1473 if( $user_id ne $e->requestor->id ) {
1474 return $e->event unless
1475 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1478 # run this inside a transaction to prevent replication delay errors
1479 my $ses = $U->start_db_session();
1480 my $s = $ses->request(
1481 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1482 $U->rollback_db_session($ses);
1489 __PACKAGE__->register_method(
1490 method => "user_transactions",
1491 api_name => "open-ils.actor.user.transactions",
1492 notes => <<" NOTES");
1493 Returns a list of open user transactions (mbts objects);
1494 Params are login_session, user_id
1495 Optional third parameter is the transactions type. defaults to all
1498 __PACKAGE__->register_method(
1499 method => "user_transactions",
1500 api_name => "open-ils.actor.user.transactions.have_charge",
1501 notes => <<" NOTES");
1502 Returns a list of all open user transactions (mbts objects) that have an initial charge
1503 Params are login_session, user_id
1504 Optional third parameter is the transactions type. defaults to all
1507 __PACKAGE__->register_method(
1508 method => "user_transactions",
1509 api_name => "open-ils.actor.user.transactions.have_balance",
1510 notes => <<" NOTES");
1511 Returns a list of all open user transactions (mbts objects) that have a balance
1512 Params are login_session, user_id
1513 Optional third parameter is the transactions type. defaults to all
1516 __PACKAGE__->register_method(
1517 method => "user_transactions",
1518 api_name => "open-ils.actor.user.transactions.fleshed",
1519 notes => <<" NOTES");
1520 Returns an object/hash of transaction, circ, title where transaction = an open
1521 user transactions (mbts objects), circ is the attached circluation, and title
1522 is the title the circ points to
1523 Params are login_session, user_id
1524 Optional third parameter is the transactions type. defaults to all
1527 __PACKAGE__->register_method(
1528 method => "user_transactions",
1529 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1530 notes => <<" NOTES");
1531 Returns an object/hash of transaction, circ, title where transaction = an open
1532 user transactions that has an initial charge (mbts objects), circ is the
1533 attached circluation, and title is the title the circ points to
1534 Params are login_session, user_id
1535 Optional third parameter is the transactions type. defaults to all
1538 __PACKAGE__->register_method(
1539 method => "user_transactions",
1540 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1541 notes => <<" NOTES");
1542 Returns an object/hash of transaction, circ, title where transaction = an open
1543 user transaction that has a balance (mbts objects), circ is the attached
1544 circluation, and title is the title the circ points to
1545 Params are login_session, user_id
1546 Optional third parameter is the transaction type. defaults to all
1549 __PACKAGE__->register_method(
1550 method => "user_transactions",
1551 api_name => "open-ils.actor.user.transactions.count",
1552 notes => <<" NOTES");
1553 Returns an object/hash of transaction, circ, title where transaction = an open
1554 user transactions (mbts objects), circ is the attached circluation, and title
1555 is the title the circ points to
1556 Params are login_session, user_id
1557 Optional third parameter is the transactions type. defaults to all
1560 __PACKAGE__->register_method(
1561 method => "user_transactions",
1562 api_name => "open-ils.actor.user.transactions.have_charge.count",
1563 notes => <<" NOTES");
1564 Returns an object/hash of transaction, circ, title where transaction = an open
1565 user transactions that has an initial charge (mbts objects), circ is the
1566 attached circluation, and title is the title the circ points to
1567 Params are login_session, user_id
1568 Optional third parameter is the transactions type. defaults to all
1571 __PACKAGE__->register_method(
1572 method => "user_transactions",
1573 api_name => "open-ils.actor.user.transactions.have_balance.count",
1574 notes => <<" NOTES");
1575 Returns an object/hash of transaction, circ, title where transaction = an open
1576 user transaction that has a balance (mbts objects), circ is the attached
1577 circluation, and title is the title the circ points to
1578 Params are login_session, user_id
1579 Optional third parameter is the transaction type. defaults to all
1582 __PACKAGE__->register_method(
1583 method => "user_transactions",
1584 api_name => "open-ils.actor.user.transactions.have_balance.total",
1585 notes => <<" NOTES");
1586 Returns an object/hash of transaction, circ, title where transaction = an open
1587 user transaction that has a balance (mbts objects), circ is the attached
1588 circluation, and title is the title the circ points to
1589 Params are login_session, user_id
1590 Optional third parameter is the transaction type. defaults to all
1595 sub user_transactions {
1596 my( $self, $client, $login_session, $user_id, $type ) = @_;
1598 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1599 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1600 return $evt if $evt;
1602 my $api = $self->api_name();
1606 if(defined($type)) { @xact = (xact_type => $type);
1608 } else { @xact = (); }
1611 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1612 ->run($login_session => $user_id => $type);
1614 if($api =~ /have_charge/o) {
1616 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1618 } elsif($api =~ /have_balance/o) {
1620 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1623 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1627 if($api =~ /total/o) {
1629 for my $t (@$trans) {
1630 $total += $t->balance_owed;
1633 $logger->debug("Total balance owed by user $user_id: $total");
1637 if($api =~ /count/o) { return scalar @$trans; }
1638 if($api !~ /fleshed/o) { return $trans; }
1641 for my $t (@$trans) {
1643 if( $t->xact_type ne 'circulation' ) {
1644 push @resp, {transaction => $t};
1648 my $circ = $apputils->simple_scalar_request(
1650 "open-ils.cstore.direct.action.circulation.retrieve",
1655 my $title = $apputils->simple_scalar_request(
1657 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1658 $circ->target_copy );
1662 my $u = OpenILS::Utils::ModsParser->new();
1663 $u->start_mods_batch($title->marc());
1664 my $mods = $u->finish_mods_batch();
1665 $mods->doc_id($title->id) if $mods;
1667 push @resp, {transaction => $t, circ => $circ, record => $mods };
1675 __PACKAGE__->register_method(
1676 method => "user_transaction_retrieve",
1677 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1679 notes => <<" NOTES");
1680 Returns a fleshedtransaction record
1682 __PACKAGE__->register_method(
1683 method => "user_transaction_retrieve",
1684 api_name => "open-ils.actor.user.transaction.retrieve",
1686 notes => <<" NOTES");
1687 Returns a transaction record
1689 sub user_transaction_retrieve {
1690 my( $self, $client, $login_session, $bill_id ) = @_;
1692 # XXX I think I'm deprecated... make sure
1694 my $trans = $apputils->simple_scalar_request(
1696 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1700 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1701 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1702 return $evt if $evt;
1704 my $api = $self->api_name();
1705 if($api !~ /fleshed/o) { return $trans; }
1707 if( $trans->xact_type ne 'circulation' ) {
1708 $logger->debug("Returning non-circ transaction");
1709 return {transaction => $trans};
1712 my $circ = $apputils->simple_scalar_request(
1714 "open-ils..direct.action.circulation.retrieve",
1717 return {transaction => $trans} unless $circ;
1718 $logger->debug("Found the circ transaction");
1720 my $title = $apputils->simple_scalar_request(
1722 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1723 $circ->target_copy );
1725 return {transaction => $trans, circ => $circ } unless $title;
1726 $logger->debug("Found the circ title");
1730 my $u = OpenILS::Utils::ModsParser->new();
1731 $u->start_mods_batch($title->marc());
1732 $mods = $u->finish_mods_batch();
1734 if ($title->id == OILS_PRECAT_RECORD) {
1735 my $copy = $apputils->simple_scalar_request(
1737 "open-ils.cstore.direct.asset.copy.retrieve",
1738 $circ->target_copy );
1740 $mods = new Fieldmapper::metabib::virtual_record;
1741 $mods->doc_id(OILS_PRECAT_RECORD);
1742 $mods->title($copy->dummy_title);
1743 $mods->author($copy->dummy_author);
1747 $logger->debug("MODSized the circ title");
1749 return {transaction => $trans, circ => $circ, record => $mods };
1753 __PACKAGE__->register_method(
1754 method => "hold_request_count",
1755 api_name => "open-ils.actor.user.hold_requests.count",
1758 notes => <<" NOTES");
1759 Returns hold ready/total counts
1761 sub hold_request_count {
1762 my( $self, $client, $login_session, $userid ) = @_;
1764 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1765 $login_session, $userid, 'VIEW_HOLD' );
1766 return $evt if $evt;
1769 my $holds = $apputils->simple_scalar_request(
1771 "open-ils.cstore.direct.action.hold_request.search.atomic",
1774 fulfillment_time => {"=" => undef },
1775 cancel_time => undef,
1780 for my $h (@$holds) {
1781 next unless $h->capture_time and $h->current_copy;
1783 my $copy = $apputils->simple_scalar_request(
1785 "open-ils.cstore.direct.asset.copy.retrieve",
1789 if ($copy and $copy->status == 8) {
1794 return { total => scalar(@$holds), ready => scalar(@ready) };
1798 __PACKAGE__->register_method(
1799 method => "checkedout_count",
1800 api_name => "open-ils.actor.user.checked_out.count__",
1802 notes => <<" NOTES");
1803 Returns a transaction record
1807 sub checkedout_count {
1808 my( $self, $client, $login_session, $userid ) = @_;
1810 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1811 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1812 return $evt if $evt;
1814 my $circs = $apputils->simple_scalar_request(
1816 "open-ils.cstore.direct.action.circulation.search.atomic",
1817 { usr => $userid, stop_fines => undef }
1818 #{ usr => $userid, checkin_time => {"=" => undef } }
1821 my $parser = DateTime::Format::ISO8601->new;
1824 for my $c (@$circs) {
1825 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1826 my $due = $due_dt->epoch;
1828 if ($due < DateTime->today->epoch) {
1833 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1837 __PACKAGE__->register_method(
1838 method => "checked_out",
1839 api_name => "open-ils.actor.user.checked_out",
1843 Returns a structure of circulations objects sorted by
1844 out, overdue, lost, claims_returned, long_overdue.
1845 A list of IDs are returned of each type.
1846 lost, long_overdue, and claims_returned circ will not
1847 be "finished" (there is an outstanding balance or some
1848 other pending action on the circ).
1850 The .count method also includes a 'total' field which
1851 sums all "open" circs
1855 __PACKAGE__->register_method(
1856 method => "checked_out",
1857 api_name => "open-ils.actor.user.checked_out.count",
1860 signature => q/@see open-ils.actor.user.checked_out/
1864 my( $self, $conn, $auth, $userid ) = @_;
1866 my $e = new_editor(authtoken=>$auth);
1867 return $e->event unless $e->checkauth;
1869 if( $userid ne $e->requestor->id ) {
1870 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1873 my $count = $self->api_name =~ /count/;
1874 return _checked_out( $count, $e, $userid );
1878 my( $iscount, $e, $userid ) = @_;
1881 my $meth = 'open-ils.storage.actor.user.checked_out';
1882 $meth = "$meth.count" if $iscount;
1883 return $U->storagereq($meth, $userid);
1885 # XXX Old code - moved to storage
1886 #------------------------------------------------------------------------------
1887 #------------------------------------------------------------------------------
1888 my $circs = $e->search_action_circulation(
1889 { usr => $userid, checkin_time => undef });
1891 my $parser = DateTime::Format::ISO8601->new;
1893 # split the circs up into overdue and not-overdue circs
1895 for my $c (@$circs) {
1896 if( $c->due_date ) {
1897 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1898 my $due = $due_dt->epoch;
1899 if ($due < DateTime->today->epoch) {
1909 my( @open, @od, @lost, @cr, @lo );
1911 while (my $c = shift(@out)) {
1912 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1913 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1914 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1915 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1918 while (my $c = shift(@overdue)) {
1919 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1920 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1921 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1922 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1927 total => @open + @od + @lost + @cr + @lo,
1928 out => scalar(@open),
1929 overdue => scalar(@od),
1930 lost => scalar(@lost),
1931 claims_returned => scalar(@cr),
1932 long_overdue => scalar(@lo)
1940 claims_returned => \@cr,
1941 long_overdue => \@lo
1946 sub _checked_out_WHAT {
1947 my( $iscount, $e, $userid ) = @_;
1949 my $circs = $e->search_action_circulation(
1950 { usr => $userid, stop_fines => undef });
1952 my $mcircs = $e->search_action_circulation(
1955 checkin_time => undef,
1956 xact_finish => undef,
1960 push( @$circs, @$mcircs );
1962 my $parser = DateTime::Format::ISO8601->new;
1964 # split the circs up into overdue and not-overdue circs
1966 for my $c (@$circs) {
1967 if( $c->due_date ) {
1968 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1969 my $due = $due_dt->epoch;
1970 if ($due < DateTime->today->epoch) {
1971 push @overdue, $c->id;
1980 # grab all of the lost, claims-returned, and longoverdue circs
1981 #my $open = $e->search_action_circulation(
1982 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1985 # these items have stop_fines, but no xact_finish, so money
1986 # is owed on them and they have not been checked in
1987 my $open = $e->search_action_circulation(
1990 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1991 xact_finish => undef,
1992 checkin_time => undef,
1997 my( @lost, @cr, @lo );
1998 for my $c (@$open) {
1999 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2000 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2001 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2007 total => @$circs + @lost + @cr + @lo,
2008 out => scalar(@out),
2009 overdue => scalar(@overdue),
2010 lost => scalar(@lost),
2011 claims_returned => scalar(@cr),
2012 long_overdue => scalar(@lo)
2018 overdue => \@overdue,
2020 claims_returned => \@cr,
2021 long_overdue => \@lo
2027 __PACKAGE__->register_method(
2028 method => "checked_in_with_fines",
2029 api_name => "open-ils.actor.user.checked_in_with_fines",
2032 signature => q/@see open-ils.actor.user.checked_out/
2034 sub checked_in_with_fines {
2035 my( $self, $conn, $auth, $userid ) = @_;
2037 my $e = new_editor(authtoken=>$auth);
2038 return $e->event unless $e->checkauth;
2040 if( $userid ne $e->requestor->id ) {
2041 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2044 # money is owed on these items and they are checked in
2045 my $open = $e->search_action_circulation(
2048 xact_finish => undef,
2049 checkin_time => { "!=" => undef },
2054 my( @lost, @cr, @lo );
2055 for my $c (@$open) {
2056 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2057 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2058 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2063 claims_returned => \@cr,
2064 long_overdue => \@lo
2076 __PACKAGE__->register_method(
2077 method => "user_transaction_history",
2078 api_name => "open-ils.actor.user.transactions.history",
2080 notes => <<" NOTES");
2081 Returns a list of billable transaction ids for a user, optionally by type
2083 __PACKAGE__->register_method(
2084 method => "user_transaction_history",
2085 api_name => "open-ils.actor.user.transactions.history.have_charge",
2087 notes => <<" NOTES");
2088 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2090 __PACKAGE__->register_method(
2091 method => "user_transaction_history",
2092 api_name => "open-ils.actor.user.transactions.history.have_balance",
2095 notes => <<" NOTES");
2096 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2098 __PACKAGE__->register_method(
2099 method => "user_transaction_history",
2100 api_name => "open-ils.actor.user.transactions.history.still_open",
2102 notes => <<" NOTES");
2103 Returns a list of billable transaction ids for a user that are not finished
2105 __PACKAGE__->register_method(
2106 method => "user_transaction_history",
2107 api_name => "open-ils.actor.user.transactions.history.have_bill",
2110 notes => <<" NOTES");
2111 Returns a list of billable transaction ids for a user that has billings
2117 sub _user_transaction_history {
2118 my( $self, $client, $login_session, $user_id, $type ) = @_;
2120 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2121 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2122 return $evt if $evt;
2124 my $api = $self->api_name();
2129 @xact = (xact_type => $type) if(defined($type));
2130 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2131 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2133 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2135 my $trans = $apputils->simple_scalar_request(
2137 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2138 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2140 return [ map { $_->id } @$trans ];
2144 =head SEE APPUTILS.PM
2149 for my $x (@xacts) {
2150 my $s = new Fieldmapper::money::billable_transaction_summary;
2153 $s->xact_start( $x->xact_start );
2154 $s->xact_finish( $x->xact_finish );
2158 for my $b (@{ $x->billings }) {
2159 next if ($U->is_true($b->voided));
2160 $to += ($b->amount * 100);
2161 $lb ||= $b->billing_ts;
2162 if ($b->billing_ts ge $lb) {
2163 $lb = $b->billing_ts;
2164 $s->last_billing_note($b->note);
2165 $s->last_billing_ts($b->billing_ts);
2166 $s->last_billing_type($b->billing_type);
2170 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2174 for my $p (@{ $x->payments }) {
2175 next if ($U->is_true($p->voided));
2176 $tp += ($p->amount * 100);
2177 $lp ||= $p->payment_ts;
2178 if ($p->payment_ts ge $lp) {
2179 $lp = $p->payment_ts;
2180 $s->last_payment_note($p->note);
2181 $s->last_payment_ts($p->payment_ts);
2182 $s->last_payment_type($p->payment_type);
2185 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2187 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2189 $s->xact_type( 'grocery' ) if ($x->grocery);
2190 $s->xact_type( 'circulation' ) if ($x->circulation);
2199 sub user_transaction_history {
2200 my( $self, $conn, $auth, $userid, $type ) = @_;
2202 # run inside of a transaction to prevent replication delays
2203 my $e = new_editor(xact=>1, authtoken=>$auth);
2204 return $e->die_event unless $e->checkauth;
2206 if( $e->requestor->id ne $userid ) {
2207 return $e->die_event
2208 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2211 my $api = $self->api_name;
2212 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2214 my @xacts = @{ $e->search_money_billable_transaction(
2215 [ { usr => $userid, @xact_finish },
2217 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2218 order_by => { mbt => 'xact_start DESC' },
2226 #my @mbts = _make_mbts( @xacts );
2227 my @mbts = $U->make_mbts( @xacts );
2229 if(defined($type)) {
2230 @mbts = grep { $_->xact_type eq $type } @mbts;
2233 if($api =~ /have_balance/o) {
2234 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2237 if($api =~ /have_charge/o) {
2238 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2241 if($api =~ /have_bill/o) {
2242 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2250 __PACKAGE__->register_method(
2251 method => "user_perms",
2252 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2254 notes => <<" NOTES");
2255 Returns a list of permissions
2258 my( $self, $client, $authtoken, $user ) = @_;
2260 my( $staff, $evt ) = $apputils->checkses($authtoken);
2261 return $evt if $evt;
2263 $user ||= $staff->id;
2265 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2269 return $apputils->simple_scalar_request(
2271 "open-ils.storage.permission.user_perms.atomic",
2275 __PACKAGE__->register_method(
2276 method => "retrieve_perms",
2277 api_name => "open-ils.actor.permissions.retrieve",
2278 notes => <<" NOTES");
2279 Returns a list of permissions
2281 sub retrieve_perms {
2282 my( $self, $client ) = @_;
2283 return $apputils->simple_scalar_request(
2285 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2286 { id => { '!=' => undef } }
2290 __PACKAGE__->register_method(
2291 method => "retrieve_groups",
2292 api_name => "open-ils.actor.groups.retrieve",
2293 notes => <<" NOTES");
2294 Returns a list of user groupss
2296 sub retrieve_groups {
2297 my( $self, $client ) = @_;
2298 return new_editor()->retrieve_all_permission_grp_tree();
2301 __PACKAGE__->register_method(
2302 method => "retrieve_org_address",
2303 api_name => "open-ils.actor.org_unit.address.retrieve",
2304 notes => <<' NOTES');
2305 Returns an org_unit address by ID
2306 @param An org_address ID
2308 sub retrieve_org_address {
2309 my( $self, $client, $id ) = @_;
2310 return $apputils->simple_scalar_request(
2312 "open-ils.cstore.direct.actor.org_address.retrieve",
2317 __PACKAGE__->register_method(
2318 method => "retrieve_groups_tree",
2319 api_name => "open-ils.actor.groups.tree.retrieve",
2320 notes => <<" NOTES");
2321 Returns a list of user groups
2323 sub retrieve_groups_tree {
2324 my( $self, $client ) = @_;
2325 return new_editor()->search_permission_grp_tree(
2330 flesh_fields => { pgt => ["children"] },
2331 order_by => { pgt => 'name'}
2338 # turns an org list into an org tree
2340 sub build_group_tree {
2342 my( $self, $grplist) = @_;
2344 return $grplist unless (
2345 ref($grplist) and @$grplist > 1 );
2347 my @list = sort { $a->name cmp $b->name } @$grplist;
2350 for my $grp (@list) {
2352 if ($grp and !defined($grp->parent)) {
2356 my ($parent) = grep { $_->id == $grp->parent} @list;
2358 $parent->children([]) unless defined($parent->children);
2359 push( @{$parent->children}, $grp );
2367 __PACKAGE__->register_method(
2368 method => "add_user_to_groups",
2369 api_name => "open-ils.actor.user.set_groups",
2370 notes => <<" NOTES");
2371 Adds a user to one or more permission groups
2374 sub add_user_to_groups {
2375 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2377 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2378 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2379 return $evt if $evt;
2381 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2382 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2383 return $evt if $evt;
2385 $apputils->simplereq(
2387 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2389 for my $group (@$groups) {
2390 my $link = Fieldmapper::permission::usr_grp_map->new;
2392 $link->usr($userid);
2394 my $id = $apputils->simplereq(
2396 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2402 __PACKAGE__->register_method(
2403 method => "get_user_perm_groups",
2404 api_name => "open-ils.actor.user.get_groups",
2405 notes => <<" NOTES");
2406 Retrieve a user's permission groups.
2410 sub get_user_perm_groups {
2411 my( $self, $client, $authtoken, $userid ) = @_;
2413 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2414 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2415 return $evt if $evt;
2417 return $apputils->simplereq(
2419 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2423 __PACKAGE__->register_method(
2424 method => "get_user_work_ous",
2425 api_name => "open-ils.actor.user.get_work_ous",
2426 notes => <<" NOTES");
2427 Retrieve a user's work org units.
2429 __PACKAGE__->register_method(
2430 method => "get_user_work_ous",
2431 api_name => "open-ils.actor.user.get_work_ous.ids",
2432 notes => <<" NOTES");
2433 Retrieve a user's work org units.
2437 sub get_user_work_ous {
2438 my( $self, $client, $auth, $userid ) = @_;
2439 my $e = new_editor(authtoken=>$auth);
2440 return $e->event unless $e->checkauth;
2441 $userid ||= $e->requestor->id;
2443 if($e->requestor->id != $userid) {
2444 my $user = $e->retrieve_actor_user($userid)
2445 or return $e->event;
2446 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2449 return $e->search_permission_usr_work_ou_map({usr => $userid})
2450 unless $self->api_name =~ /.ids$/;
2452 # client just wants a list of org IDs
2453 return $U->get_user_work_ou_ids($e, $userid);
2459 __PACKAGE__->register_method (
2460 method => 'register_workstation',
2461 api_name => 'open-ils.actor.workstation.register.override',
2462 signature => q/@see open-ils.actor.workstation.register/);
2464 __PACKAGE__->register_method (
2465 method => 'register_workstation',
2466 api_name => 'open-ils.actor.workstation.register',
2468 Registers a new workstion in the system
2469 @param authtoken The login session key
2470 @param name The name of the workstation id
2471 @param owner The org unit that owns this workstation
2472 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2473 if the name is already in use.
2476 sub register_workstation {
2477 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2479 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2480 return $e->die_event unless $e->checkauth;
2481 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2482 my $existing = $e->search_actor_workstation({name => $name})->[0];
2486 if( $self->api_name =~ /override/o ) {
2487 # workstation with the given name exists.
2489 if($owner ne $existing->owning_lib) {
2490 # if necessary, update the owning_lib of the workstation
2492 $logger->info("changing owning lib of workstation ".$existing->id.
2493 " from ".$existing->owning_lib." to $owner");
2494 return $e->die_event unless
2495 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2497 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2499 $existing->owning_lib($owner);
2500 return $e->die_event unless $e->update_actor_workstation($existing);
2506 "attempt to register an existing workstation. returning existing ID");
2509 return $existing->id;
2512 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2516 my $ws = Fieldmapper::actor::workstation->new;
2517 $ws->owning_lib($owner);
2519 $e->create_actor_workstation($ws) or return $e->die_event;
2521 return $ws->id; # note: editor sets the id on the new object for us
2524 __PACKAGE__->register_method (
2525 method => 'workstation_list',
2526 api_name => 'open-ils.actor.workstation.list',
2528 Returns a list of workstations registered at the given location
2529 @param authtoken The login session key
2530 @param ids A list of org_unit.id's for the workstation owners
2533 sub workstation_list {
2534 my( $self, $conn, $authtoken, @orgs ) = @_;
2536 my $e = new_editor(authtoken=>$authtoken);
2537 return $e->event unless $e->checkauth;
2542 unless $e->allowed('REGISTER_WORKSTATION', $o);
2543 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2554 __PACKAGE__->register_method (
2555 method => 'fetch_patron_note',
2556 api_name => 'open-ils.actor.note.retrieve.all',
2559 Returns a list of notes for a given user
2560 Requestor must have VIEW_USER permission if pub==false and
2561 @param authtoken The login session key
2562 @param args Hash of params including
2563 patronid : the patron's id
2564 pub : true if retrieving only public notes
2568 sub fetch_patron_note {
2569 my( $self, $conn, $authtoken, $args ) = @_;
2570 my $patronid = $$args{patronid};
2572 my($reqr, $evt) = $U->checkses($authtoken);
2573 return $evt if $evt;
2576 ($patron, $evt) = $U->fetch_user($patronid);
2577 return $evt if $evt;
2580 if( $patronid ne $reqr->id ) {
2581 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2582 return $evt if $evt;
2584 return $U->cstorereq(
2585 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2586 { usr => $patronid, pub => 't' } );
2589 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2590 return $evt if $evt;
2592 return $U->cstorereq(
2593 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2596 __PACKAGE__->register_method (
2597 method => 'create_user_note',
2598 api_name => 'open-ils.actor.note.create',
2600 Creates a new note for the given user
2601 @param authtoken The login session key
2602 @param note The note object
2605 sub create_user_note {
2606 my( $self, $conn, $authtoken, $note ) = @_;
2607 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2608 return $e->die_event unless $e->checkauth;
2610 my $user = $e->retrieve_actor_user($note->usr)
2611 or return $e->die_event;
2613 return $e->die_event unless
2614 $e->allowed('UPDATE_USER',$user->home_ou);
2616 $note->creator($e->requestor->id);
2617 $e->create_actor_usr_note($note) or return $e->die_event;
2623 __PACKAGE__->register_method (
2624 method => 'delete_user_note',
2625 api_name => 'open-ils.actor.note.delete',
2627 Deletes a note for the given user
2628 @param authtoken The login session key
2629 @param noteid The note id
2632 sub delete_user_note {
2633 my( $self, $conn, $authtoken, $noteid ) = @_;
2635 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2636 return $e->die_event unless $e->checkauth;
2637 my $note = $e->retrieve_actor_usr_note($noteid)
2638 or return $e->die_event;
2639 my $user = $e->retrieve_actor_user($note->usr)
2640 or return $e->die_event;
2641 return $e->die_event unless
2642 $e->allowed('UPDATE_USER', $user->home_ou);
2644 $e->delete_actor_usr_note($note) or return $e->die_event;
2650 __PACKAGE__->register_method (
2651 method => 'update_user_note',
2652 api_name => 'open-ils.actor.note.update',
2654 @param authtoken The login session key
2655 @param note The note
2659 sub update_user_note {
2660 my( $self, $conn, $auth, $note ) = @_;
2661 my $e = new_editor(authtoken=>$auth, xact=>1);
2662 return $e->event unless $e->checkauth;
2663 my $patron = $e->retrieve_actor_user($note->usr)
2664 or return $e->event;
2665 return $e->event unless
2666 $e->allowed('UPDATE_USER', $patron->home_ou);
2667 $e->update_actor_user_note($note)
2668 or return $e->event;
2676 __PACKAGE__->register_method (
2677 method => 'create_closed_date',
2678 api_name => 'open-ils.actor.org_unit.closed_date.create',
2680 Creates a new closing entry for the given org_unit
2681 @param authtoken The login session key
2682 @param note The closed_date object
2685 sub create_closed_date {
2686 my( $self, $conn, $authtoken, $cd ) = @_;
2688 my( $user, $evt ) = $U->checkses($authtoken);
2689 return $evt if $evt;
2691 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2692 return $evt if $evt;
2694 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2696 my $id = $U->storagereq(
2697 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2698 return $U->DB_UPDATE_FAILED($cd) unless $id;
2703 __PACKAGE__->register_method (
2704 method => 'delete_closed_date',
2705 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2707 Deletes a closing entry for the given org_unit
2708 @param authtoken The login session key
2709 @param noteid The close_date id
2712 sub delete_closed_date {
2713 my( $self, $conn, $authtoken, $cd ) = @_;
2715 my( $user, $evt ) = $U->checkses($authtoken);
2716 return $evt if $evt;
2719 ($cd_obj, $evt) = fetch_closed_date($cd);
2720 return $evt if $evt;
2722 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2723 return $evt if $evt;
2725 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2727 my $stat = $U->storagereq(
2728 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2729 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2734 __PACKAGE__->register_method(
2735 method => 'usrname_exists',
2736 api_name => 'open-ils.actor.username.exists',
2738 Returns 1 if the requested username exists, returns 0 otherwise
2742 sub usrname_exists {
2743 my( $self, $conn, $auth, $usrname ) = @_;
2744 my $e = new_editor(authtoken=>$auth);
2745 return $e->event unless $e->checkauth;
2746 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2747 return $$a[0] if $a and @$a;
2751 __PACKAGE__->register_method(
2752 method => 'barcode_exists',
2753 api_name => 'open-ils.actor.barcode.exists',
2756 Returns 1 if the requested barcode exists, returns 0 otherwise
2760 sub barcode_exists {
2761 my( $self, $conn, $auth, $barcode ) = @_;
2762 my $e = new_editor(authtoken=>$auth);
2763 return $e->event unless $e->checkauth;
2764 my $card = $e->search_actor_card({barcode => $barcode});
2765 return undef unless @$card;
2766 return $card->[0]->usr;
2770 __PACKAGE__->register_method(
2771 method => 'retrieve_net_levels',
2772 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2775 sub retrieve_net_levels {
2776 my( $self, $conn, $auth ) = @_;
2777 my $e = new_editor(authtoken=>$auth);
2778 return $e->event unless $e->checkauth;
2779 return $e->retrieve_all_config_net_access_level();
2783 __PACKAGE__->register_method(
2784 method => 'fetch_org_by_shortname',
2785 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2787 sub fetch_org_by_shortname {
2788 my( $self, $conn, $sname ) = @_;
2789 my $e = new_editor();
2790 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2791 return $e->event unless $org;
2796 __PACKAGE__->register_method(
2797 method => 'session_home_lib',
2798 api_name => 'open-ils.actor.session.home_lib',
2801 sub session_home_lib {
2802 my( $self, $conn, $auth ) = @_;
2803 my $e = new_editor(authtoken=>$auth);
2804 return undef unless $e->checkauth;
2805 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2806 return $org->shortname;
2809 __PACKAGE__->register_method(
2810 method => 'session_safe_token',
2811 api_name => 'open-ils.actor.session.safe_token',
2813 Returns a hashed session ID that is safe for export to the world.
2814 This safe token will expire after 1 hour of non-use.
2815 @param auth Active authentication token
2819 sub session_safe_token {
2820 my( $self, $conn, $auth ) = @_;
2821 my $e = new_editor(authtoken=>$auth);
2822 return undef unless $e->checkauth;
2824 my $safe_token = md5_hex($auth);
2826 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2828 # Add more like the following if needed...
2830 "safe-token-home_lib-shortname-$safe_token",
2831 $e->retrieve_actor_org_unit(
2832 $e->requestor->home_ou
2841 __PACKAGE__->register_method(
2842 method => 'safe_token_home_lib',
2843 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2845 Returns the home library shortname from the session
2846 asscociated with a safe token from generated by
2847 open-ils.actor.session.safe_token.
2848 @param safe_token Active safe token
2852 sub safe_token_home_lib {
2853 my( $self, $conn, $safe_token ) = @_;
2855 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2856 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2861 __PACKAGE__->register_method(
2862 method => 'slim_tree',
2863 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2866 my $tree = new_editor()->search_actor_org_unit(
2868 {"parent_ou" => undef },
2871 flesh_fields => { aou => ['children'] },
2872 order_by => { aou => 'name'},
2873 select => { aou => ["id","shortname", "name"]},
2878 return trim_tree($tree);
2884 return undef unless $tree;
2886 code => $tree->shortname,
2887 name => $tree->name,
2889 if( $tree->children and @{$tree->children} ) {
2890 $htree->{children} = [];
2891 for my $c (@{$tree->children}) {
2892 push( @{$htree->{children}}, trim_tree($c) );
2900 __PACKAGE__->register_method(
2901 method => "update_penalties",
2902 api_name => "open-ils.actor.user.penalties.update");
2903 sub update_penalties {
2904 my( $self, $conn, $auth, $userid ) = @_;
2905 my $e = new_editor(authtoken=>$auth);
2906 return $e->event unless $e->checkauth;
2907 $U->update_patron_penalties(
2909 patronid => $userid,
2916 __PACKAGE__->register_method(
2917 method => "user_retrieve_fleshed_by_id",
2918 api_name => "open-ils.actor.user.fleshed.retrieve",);
2920 sub user_retrieve_fleshed_by_id {
2921 my( $self, $client, $auth, $user_id, $fields ) = @_;
2922 my $e = new_editor(authtoken => $auth);
2923 return $e->event unless $e->checkauth;
2925 if( $e->requestor->id != $user_id ) {
2926 return $e->event unless $e->allowed('VIEW_USER');
2932 "standing_penalties",
2936 "stat_cat_entries" ];
2937 return new_flesh_user($user_id, $fields, $e);
2941 sub new_flesh_user {
2944 my $fields = shift || [];
2945 my $e = shift || new_editor(xact=>1);
2947 my $user = $e->retrieve_actor_user(
2952 "flesh_fields" => { "au" => $fields }
2955 ) or return $e->event;
2958 if( grep { $_ eq 'addresses' } @$fields ) {
2960 $user->addresses([]) unless @{$user->addresses};
2962 if( ref $user->billing_address ) {
2963 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2964 push( @{$user->addresses}, $user->billing_address );
2968 if( ref $user->mailing_address ) {
2969 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2970 push( @{$user->addresses}, $user->mailing_address );
2976 $user->clear_passwd();
2983 __PACKAGE__->register_method(
2984 method => "user_retrieve_parts",
2985 api_name => "open-ils.actor.user.retrieve.parts",);
2987 sub user_retrieve_parts {
2988 my( $self, $client, $auth, $user_id, $fields ) = @_;
2989 my $e = new_editor(authtoken => $auth);
2990 return $e->event unless $e->checkauth;
2991 if( $e->requestor->id != $user_id ) {
2992 return $e->event unless $e->allowed('VIEW_USER');
2995 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2996 push(@resp, $user->$_()) for(@$fields);
3002 __PACKAGE__->register_method(
3003 method => 'user_opt_in_enabled',
3004 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
3006 @return 1 if user opt-in is globally enabled, 0 otherwise.
3009 sub user_opt_in_enabled {
3010 my($self, $conn) = @_;
3011 my $sc = OpenSRF::Utils::SettingsClient->new;
3012 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
3017 __PACKAGE__->register_method(
3018 method => 'user_opt_in_at_org',
3019 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
3021 @param $auth The auth token
3022 @param user_id The ID of the user to test
3023 @return 1 if the user has opted in at the specified org,
3024 event on error, and 0 otherwise. /);
3025 sub user_opt_in_at_org {
3026 my($self, $conn, $auth, $user_id) = @_;
3028 # see if we even need to enforce the opt-in value
3029 return 1 unless user_opt_in_enabled($self);
3031 my $e = new_editor(authtoken => $auth);
3032 return $e->event unless $e->checkauth;
3033 my $org_id = $e->requestor->ws_ou;
3035 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3036 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3038 # user is automatically opted-in at the home org
3039 return 1 if $user->home_ou eq $org_id;
3041 my $vals = $e->search_actor_usr_org_unit_opt_in(
3042 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3048 __PACKAGE__->register_method(
3049 method => 'create_user_opt_in_at_org',
3050 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3052 @param $auth The auth token
3053 @param user_id The ID of the user to test
3054 @return The ID of the newly created object, event on error./);
3056 sub create_user_opt_in_at_org {
3057 my($self, $conn, $auth, $user_id) = @_;
3059 my $e = new_editor(authtoken => $auth, xact=>1);
3060 return $e->die_event unless $e->checkauth;
3061 my $org_id = $e->requestor->ws_ou;
3063 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3064 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3066 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3068 $opt_in->org_unit($org_id);
3069 $opt_in->usr($user_id);
3070 $opt_in->staff($e->requestor->id);
3071 $opt_in->opt_in_ts('now');
3072 $opt_in->opt_in_ws($e->requestor->wsid);
3074 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3075 or return $e->die_event;
3083 __PACKAGE__->register_method (
3084 method => 'retrieve_org_hours',
3085 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
3087 Returns the hours of operation for a specified org unit
3088 @param authtoken The login session key
3089 @param org_id The org_unit ID
3093 sub retrieve_org_hours {
3094 my($self, $conn, $auth, $org_id) = @_;
3095 my $e = new_editor(authtoken => $auth);
3096 return $e->die_event unless $e->checkauth;
3097 $org_id ||= $e->requestor->ws_ou;
3098 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);