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 ($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 || !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
860 #warn( "Updating permissions with method $method and session $ses and map $map" );
861 $logger->info( "Updating permissions with method $method and map $map" );
863 my $stat = $session->request($method, $map)->gather(1);
864 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
868 $apputils->commit_db_session($session);
870 return scalar(@$maps);
874 sub _create_standing_penalties {
876 my($session, $user_session, $patron, $new_patron) = @_;
878 my $maps = $patron->standing_penalties;
881 for my $map (@$maps) {
883 if ($map->isdeleted()) {
884 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
885 } elsif ($map->isnew()) {
886 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
892 $map->usr($new_patron->id);
894 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
896 my $stat = $session->request($method, $map)->gather(1);
897 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
900 return ($new_patron, undef);
905 __PACKAGE__->register_method(
906 method => "search_username",
907 api_name => "open-ils.actor.user.search.username",
910 sub search_username {
911 my($self, $client, $username) = @_;
912 return new_editor()->search_actor_user({usrname=>$username});
918 __PACKAGE__->register_method(
919 method => "user_retrieve_by_barcode",
921 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
923 sub user_retrieve_by_barcode {
924 my($self, $client, $user_session, $barcode) = @_;
926 $logger->debug("Searching for user with barcode $barcode");
927 my ($user_obj, $evt) = $apputils->checkses($user_session);
930 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
932 "open-ils.cstore.direct.actor.card.search.atomic",
933 { barcode => $barcode }
936 if(!$card || !$card->[0]) {
937 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
941 my $user = flesh_user($card->usr());
943 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
946 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
953 __PACKAGE__->register_method(
954 method => "get_user_by_id",
955 api_name => "open-ils.actor.user.retrieve",);
958 my ($self, $client, $auth, $id) = @_;
959 my $e = new_editor(authtoken=>$auth);
960 return $e->event unless $e->checkauth;
961 my $user = $e->retrieve_actor_user($id)
963 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
969 __PACKAGE__->register_method(
970 method => "get_org_types",
971 api_name => "open-ils.actor.org_types.retrieve",);
974 return $U->get_org_types();
979 __PACKAGE__->register_method(
980 method => "get_user_ident_types",
981 api_name => "open-ils.actor.user.ident_types.retrieve",
984 sub get_user_ident_types {
985 return $ident_types if $ident_types;
986 return $ident_types =
987 new_editor()->retrieve_all_config_identification_type();
993 __PACKAGE__->register_method(
994 method => "get_org_unit",
995 api_name => "open-ils.actor.org_unit.retrieve",
999 my( $self, $client, $user_session, $org_id ) = @_;
1000 my $e = new_editor(authtoken => $user_session);
1002 return $e->event unless $e->checkauth;
1003 $org_id = $e->requestor->ws_ou;
1005 my $o = $e->retrieve_actor_org_unit($org_id)
1006 or return $e->event;
1010 __PACKAGE__->register_method(
1011 method => "search_org_unit",
1012 api_name => "open-ils.actor.org_unit_list.search",
1015 sub search_org_unit {
1017 my( $self, $client, $field, $value ) = @_;
1019 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1021 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1022 { $field => $value } );
1028 # build the org tree
1030 __PACKAGE__->register_method(
1031 method => "get_org_tree",
1032 api_name => "open-ils.actor.org_tree.retrieve",
1034 note => "Returns the entire org tree structure",
1038 my( $self, $client) = @_;
1039 return $U->get_org_tree();
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 flat list of all of the org_units where the user
1334 has the requested permission.
1338 __PACKAGE__->register_method(
1339 method => 'check_user_work_perms',
1340 api_name => 'open-ils.actor.user.work_perm.org_id_list',
1343 @see open-ils.actor.user.work_perm.highest_org_set
1344 Returns a flat list of all of the org_units where the user
1345 has the requested permission.
1349 sub check_user_work_perms {
1350 my($self, $conn, $auth, $perm, $options) = @_;
1351 my $e = new_editor(authtoken=>$auth);
1352 return $e->event unless $e->checkauth;
1353 my $orglist = $U->find_highest_work_orgs($e, $perm, $options);
1356 $self->api_name =~ /highest_org_set/;
1358 # build a list of org trees
1359 return get_org_descendants($self, $conn, $orglist)
1360 if $self->api_name =~ /org_tree_list/;
1363 push(@list, @{$U->get_org_descendants($_)}) for @$orglist;
1364 return \@list if $self->api_name =~ /org_id_list/;
1365 return $e->batch_retrieve_actor_org_unit(\@list);
1369 __PACKAGE__->register_method(
1370 method => 'check_user_perms4',
1371 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1373 Returns the highest org unit id at which a user has a given permission
1374 If the requestor does not match the target user, the requestor must have
1375 'VIEW_PERMISSION' rights at the home org unit of the target user
1376 @param authtoken The login session key
1377 @param userid The id of the user in question
1378 @param perms An array of perm names to check
1379 @return An array of orgId's representing the org unit
1380 highest in the org tree within which the user has the requested permission
1381 The arrah of orgId's has matches the order of the perms array
1384 sub check_user_perms4 {
1385 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1387 my( $staff, $target, $org, $evt );
1389 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1390 $authtoken, $userid, 'VIEW_PERMISSION' );
1391 return $evt if $evt;
1394 return [] unless ref($perms);
1395 my $tree = $U->get_org_tree();
1397 for my $p (@$perms) {
1398 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1406 __PACKAGE__->register_method(
1407 method => "user_fines_summary",
1408 api_name => "open-ils.actor.user.fines.summary",
1410 notes => <<" NOTES");
1411 Returns a short summary of the users total open fines, excluding voided fines
1412 Params are login_session, user_id
1413 Returns a 'mous' object.
1416 sub user_fines_summary {
1417 my( $self, $client, $auth, $user_id ) = @_;
1418 my $e = new_editor(authtoken=>$auth);
1419 return $e->event unless $e->checkauth;
1420 my $user = $e->retrieve_actor_user($user_id)
1421 or return $e->event;
1423 if( $user_id ne $e->requestor->id ) {
1424 return $e->event unless
1425 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1428 # run this inside a transaction to prevent replication delay errors
1429 my $ses = $U->start_db_session();
1430 my $s = $ses->request(
1431 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1432 $U->rollback_db_session($ses);
1439 __PACKAGE__->register_method(
1440 method => "user_transactions",
1441 api_name => "open-ils.actor.user.transactions",
1442 notes => <<" NOTES");
1443 Returns a list of open user transactions (mbts objects);
1444 Params are login_session, user_id
1445 Optional third parameter is the transactions type. defaults to all
1448 __PACKAGE__->register_method(
1449 method => "user_transactions",
1450 api_name => "open-ils.actor.user.transactions.have_charge",
1451 notes => <<" NOTES");
1452 Returns a list of all open user transactions (mbts objects) that have an initial charge
1453 Params are login_session, user_id
1454 Optional third parameter is the transactions type. defaults to all
1457 __PACKAGE__->register_method(
1458 method => "user_transactions",
1459 api_name => "open-ils.actor.user.transactions.have_balance",
1460 notes => <<" NOTES");
1461 Returns a list of all open user transactions (mbts objects) that have a balance
1462 Params are login_session, user_id
1463 Optional third parameter is the transactions type. defaults to all
1466 __PACKAGE__->register_method(
1467 method => "user_transactions",
1468 api_name => "open-ils.actor.user.transactions.fleshed",
1469 notes => <<" NOTES");
1470 Returns an object/hash of transaction, circ, title where transaction = an open
1471 user transactions (mbts objects), circ is the attached circluation, and title
1472 is the title the circ points to
1473 Params are login_session, user_id
1474 Optional third parameter is the transactions type. defaults to all
1477 __PACKAGE__->register_method(
1478 method => "user_transactions",
1479 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1480 notes => <<" NOTES");
1481 Returns an object/hash of transaction, circ, title where transaction = an open
1482 user transactions that has an initial charge (mbts objects), circ is the
1483 attached circluation, and title is the title the circ points to
1484 Params are login_session, user_id
1485 Optional third parameter is the transactions type. defaults to all
1488 __PACKAGE__->register_method(
1489 method => "user_transactions",
1490 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1491 notes => <<" NOTES");
1492 Returns an object/hash of transaction, circ, title where transaction = an open
1493 user transaction that has a balance (mbts objects), circ is the attached
1494 circluation, and title is the title the circ points to
1495 Params are login_session, user_id
1496 Optional third parameter is the transaction type. defaults to all
1499 __PACKAGE__->register_method(
1500 method => "user_transactions",
1501 api_name => "open-ils.actor.user.transactions.count",
1502 notes => <<" NOTES");
1503 Returns an object/hash of transaction, circ, title where transaction = an open
1504 user transactions (mbts objects), circ is the attached circluation, and title
1505 is the title the circ points to
1506 Params are login_session, user_id
1507 Optional third parameter is the transactions type. defaults to all
1510 __PACKAGE__->register_method(
1511 method => "user_transactions",
1512 api_name => "open-ils.actor.user.transactions.have_charge.count",
1513 notes => <<" NOTES");
1514 Returns an object/hash of transaction, circ, title where transaction = an open
1515 user transactions that has an initial charge (mbts objects), circ is the
1516 attached circluation, and title is the title the circ points to
1517 Params are login_session, user_id
1518 Optional third parameter is the transactions type. defaults to all
1521 __PACKAGE__->register_method(
1522 method => "user_transactions",
1523 api_name => "open-ils.actor.user.transactions.have_balance.count",
1524 notes => <<" NOTES");
1525 Returns an object/hash of transaction, circ, title where transaction = an open
1526 user transaction that has a balance (mbts objects), circ is the attached
1527 circluation, and title is the title the circ points to
1528 Params are login_session, user_id
1529 Optional third parameter is the transaction type. defaults to all
1532 __PACKAGE__->register_method(
1533 method => "user_transactions",
1534 api_name => "open-ils.actor.user.transactions.have_balance.total",
1535 notes => <<" NOTES");
1536 Returns an object/hash of transaction, circ, title where transaction = an open
1537 user transaction that has a balance (mbts objects), circ is the attached
1538 circluation, and title is the title the circ points to
1539 Params are login_session, user_id
1540 Optional third parameter is the transaction type. defaults to all
1545 sub user_transactions {
1546 my( $self, $client, $login_session, $user_id, $type ) = @_;
1548 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1549 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1550 return $evt if $evt;
1552 my $api = $self->api_name();
1556 if(defined($type)) { @xact = (xact_type => $type);
1558 } else { @xact = (); }
1561 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1562 ->run($login_session => $user_id => $type);
1564 if($api =~ /have_charge/o) {
1566 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1568 } elsif($api =~ /have_balance/o) {
1570 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1573 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1577 if($api =~ /total/o) {
1579 for my $t (@$trans) {
1580 $total += $t->balance_owed;
1583 $logger->debug("Total balance owed by user $user_id: $total");
1587 if($api =~ /count/o) { return scalar @$trans; }
1588 if($api !~ /fleshed/o) { return $trans; }
1591 for my $t (@$trans) {
1593 if( $t->xact_type ne 'circulation' ) {
1594 push @resp, {transaction => $t};
1598 my $circ = $apputils->simple_scalar_request(
1600 "open-ils.cstore.direct.action.circulation.retrieve",
1605 my $title = $apputils->simple_scalar_request(
1607 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1608 $circ->target_copy );
1612 my $u = OpenILS::Utils::ModsParser->new();
1613 $u->start_mods_batch($title->marc());
1614 my $mods = $u->finish_mods_batch();
1615 $mods->doc_id($title->id) if $mods;
1617 push @resp, {transaction => $t, circ => $circ, record => $mods };
1625 __PACKAGE__->register_method(
1626 method => "user_transaction_retrieve",
1627 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1629 notes => <<" NOTES");
1630 Returns a fleshedtransaction record
1632 __PACKAGE__->register_method(
1633 method => "user_transaction_retrieve",
1634 api_name => "open-ils.actor.user.transaction.retrieve",
1636 notes => <<" NOTES");
1637 Returns a transaction record
1639 sub user_transaction_retrieve {
1640 my( $self, $client, $login_session, $bill_id ) = @_;
1642 # XXX I think I'm deprecated... make sure
1644 my $trans = $apputils->simple_scalar_request(
1646 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1650 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1651 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1652 return $evt if $evt;
1654 my $api = $self->api_name();
1655 if($api !~ /fleshed/o) { return $trans; }
1657 if( $trans->xact_type ne 'circulation' ) {
1658 $logger->debug("Returning non-circ transaction");
1659 return {transaction => $trans};
1662 my $circ = $apputils->simple_scalar_request(
1664 "open-ils..direct.action.circulation.retrieve",
1667 return {transaction => $trans} unless $circ;
1668 $logger->debug("Found the circ transaction");
1670 my $title = $apputils->simple_scalar_request(
1672 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1673 $circ->target_copy );
1675 return {transaction => $trans, circ => $circ } unless $title;
1676 $logger->debug("Found the circ title");
1680 my $u = OpenILS::Utils::ModsParser->new();
1681 $u->start_mods_batch($title->marc());
1682 $mods = $u->finish_mods_batch();
1684 if ($title->id == OILS_PRECAT_RECORD) {
1685 my $copy = $apputils->simple_scalar_request(
1687 "open-ils.cstore.direct.asset.copy.retrieve",
1688 $circ->target_copy );
1690 $mods = new Fieldmapper::metabib::virtual_record;
1691 $mods->doc_id(OILS_PRECAT_RECORD);
1692 $mods->title($copy->dummy_title);
1693 $mods->author($copy->dummy_author);
1697 $logger->debug("MODSized the circ title");
1699 return {transaction => $trans, circ => $circ, record => $mods };
1703 __PACKAGE__->register_method(
1704 method => "hold_request_count",
1705 api_name => "open-ils.actor.user.hold_requests.count",
1708 notes => <<" NOTES");
1709 Returns hold ready/total counts
1711 sub hold_request_count {
1712 my( $self, $client, $login_session, $userid ) = @_;
1714 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1715 $login_session, $userid, 'VIEW_HOLD' );
1716 return $evt if $evt;
1719 my $holds = $apputils->simple_scalar_request(
1721 "open-ils.cstore.direct.action.hold_request.search.atomic",
1724 fulfillment_time => {"=" => undef },
1725 cancel_time => undef,
1730 for my $h (@$holds) {
1731 next unless $h->capture_time and $h->current_copy;
1733 my $copy = $apputils->simple_scalar_request(
1735 "open-ils.cstore.direct.asset.copy.retrieve",
1739 if ($copy and $copy->status == 8) {
1744 return { total => scalar(@$holds), ready => scalar(@ready) };
1748 __PACKAGE__->register_method(
1749 method => "checkedout_count",
1750 api_name => "open-ils.actor.user.checked_out.count__",
1752 notes => <<" NOTES");
1753 Returns a transaction record
1757 sub checkedout_count {
1758 my( $self, $client, $login_session, $userid ) = @_;
1760 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1761 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1762 return $evt if $evt;
1764 my $circs = $apputils->simple_scalar_request(
1766 "open-ils.cstore.direct.action.circulation.search.atomic",
1767 { usr => $userid, stop_fines => undef }
1768 #{ usr => $userid, checkin_time => {"=" => undef } }
1771 my $parser = DateTime::Format::ISO8601->new;
1774 for my $c (@$circs) {
1775 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1776 my $due = $due_dt->epoch;
1778 if ($due < DateTime->today->epoch) {
1783 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1787 __PACKAGE__->register_method(
1788 method => "checked_out",
1789 api_name => "open-ils.actor.user.checked_out",
1793 Returns a structure of circulations objects sorted by
1794 out, overdue, lost, claims_returned, long_overdue.
1795 A list of IDs are returned of each type.
1796 lost, long_overdue, and claims_returned circ will not
1797 be "finished" (there is an outstanding balance or some
1798 other pending action on the circ).
1800 The .count method also includes a 'total' field which
1801 sums all "open" circs
1805 __PACKAGE__->register_method(
1806 method => "checked_out",
1807 api_name => "open-ils.actor.user.checked_out.count",
1810 signature => q/@see open-ils.actor.user.checked_out/
1814 my( $self, $conn, $auth, $userid ) = @_;
1816 my $e = new_editor(authtoken=>$auth);
1817 return $e->event unless $e->checkauth;
1819 if( $userid ne $e->requestor->id ) {
1820 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1823 my $count = $self->api_name =~ /count/;
1824 return _checked_out( $count, $e, $userid );
1828 my( $iscount, $e, $userid ) = @_;
1831 my $meth = 'open-ils.storage.actor.user.checked_out';
1832 $meth = "$meth.count" if $iscount;
1833 return $U->storagereq($meth, $userid);
1835 # XXX Old code - moved to storage
1836 #------------------------------------------------------------------------------
1837 #------------------------------------------------------------------------------
1838 my $circs = $e->search_action_circulation(
1839 { usr => $userid, checkin_time => undef });
1841 my $parser = DateTime::Format::ISO8601->new;
1843 # split the circs up into overdue and not-overdue circs
1845 for my $c (@$circs) {
1846 if( $c->due_date ) {
1847 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1848 my $due = $due_dt->epoch;
1849 if ($due < DateTime->today->epoch) {
1859 my( @open, @od, @lost, @cr, @lo );
1861 while (my $c = shift(@out)) {
1862 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1863 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1864 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1865 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1868 while (my $c = shift(@overdue)) {
1869 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1870 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1871 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1872 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1877 total => @open + @od + @lost + @cr + @lo,
1878 out => scalar(@open),
1879 overdue => scalar(@od),
1880 lost => scalar(@lost),
1881 claims_returned => scalar(@cr),
1882 long_overdue => scalar(@lo)
1890 claims_returned => \@cr,
1891 long_overdue => \@lo
1896 sub _checked_out_WHAT {
1897 my( $iscount, $e, $userid ) = @_;
1899 my $circs = $e->search_action_circulation(
1900 { usr => $userid, stop_fines => undef });
1902 my $mcircs = $e->search_action_circulation(
1905 checkin_time => undef,
1906 xact_finish => undef,
1910 push( @$circs, @$mcircs );
1912 my $parser = DateTime::Format::ISO8601->new;
1914 # split the circs up into overdue and not-overdue circs
1916 for my $c (@$circs) {
1917 if( $c->due_date ) {
1918 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1919 my $due = $due_dt->epoch;
1920 if ($due < DateTime->today->epoch) {
1921 push @overdue, $c->id;
1930 # grab all of the lost, claims-returned, and longoverdue circs
1931 #my $open = $e->search_action_circulation(
1932 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1935 # these items have stop_fines, but no xact_finish, so money
1936 # is owed on them and they have not been checked in
1937 my $open = $e->search_action_circulation(
1940 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1941 xact_finish => undef,
1942 checkin_time => undef,
1947 my( @lost, @cr, @lo );
1948 for my $c (@$open) {
1949 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1950 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1951 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1957 total => @$circs + @lost + @cr + @lo,
1958 out => scalar(@out),
1959 overdue => scalar(@overdue),
1960 lost => scalar(@lost),
1961 claims_returned => scalar(@cr),
1962 long_overdue => scalar(@lo)
1968 overdue => \@overdue,
1970 claims_returned => \@cr,
1971 long_overdue => \@lo
1977 __PACKAGE__->register_method(
1978 method => "checked_in_with_fines",
1979 api_name => "open-ils.actor.user.checked_in_with_fines",
1982 signature => q/@see open-ils.actor.user.checked_out/
1984 sub checked_in_with_fines {
1985 my( $self, $conn, $auth, $userid ) = @_;
1987 my $e = new_editor(authtoken=>$auth);
1988 return $e->event unless $e->checkauth;
1990 if( $userid ne $e->requestor->id ) {
1991 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1994 # money is owed on these items and they are checked in
1995 my $open = $e->search_action_circulation(
1998 xact_finish => undef,
1999 checkin_time => { "!=" => undef },
2004 my( @lost, @cr, @lo );
2005 for my $c (@$open) {
2006 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2007 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2008 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2013 claims_returned => \@cr,
2014 long_overdue => \@lo
2026 __PACKAGE__->register_method(
2027 method => "user_transaction_history",
2028 api_name => "open-ils.actor.user.transactions.history",
2030 notes => <<" NOTES");
2031 Returns a list of billable transaction ids for a user, optionally by type
2033 __PACKAGE__->register_method(
2034 method => "user_transaction_history",
2035 api_name => "open-ils.actor.user.transactions.history.have_charge",
2037 notes => <<" NOTES");
2038 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2040 __PACKAGE__->register_method(
2041 method => "user_transaction_history",
2042 api_name => "open-ils.actor.user.transactions.history.have_balance",
2045 notes => <<" NOTES");
2046 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2048 __PACKAGE__->register_method(
2049 method => "user_transaction_history",
2050 api_name => "open-ils.actor.user.transactions.history.still_open",
2052 notes => <<" NOTES");
2053 Returns a list of billable transaction ids for a user that are not finished
2055 __PACKAGE__->register_method(
2056 method => "user_transaction_history",
2057 api_name => "open-ils.actor.user.transactions.history.have_bill",
2060 notes => <<" NOTES");
2061 Returns a list of billable transaction ids for a user that has billings
2067 sub _user_transaction_history {
2068 my( $self, $client, $login_session, $user_id, $type ) = @_;
2070 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2071 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2072 return $evt if $evt;
2074 my $api = $self->api_name();
2079 @xact = (xact_type => $type) if(defined($type));
2080 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2081 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2083 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2085 my $trans = $apputils->simple_scalar_request(
2087 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2088 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2090 return [ map { $_->id } @$trans ];
2094 =head SEE APPUTILS.PM
2099 for my $x (@xacts) {
2100 my $s = new Fieldmapper::money::billable_transaction_summary;
2103 $s->xact_start( $x->xact_start );
2104 $s->xact_finish( $x->xact_finish );
2108 for my $b (@{ $x->billings }) {
2109 next if ($U->is_true($b->voided));
2110 $to += ($b->amount * 100);
2111 $lb ||= $b->billing_ts;
2112 if ($b->billing_ts ge $lb) {
2113 $lb = $b->billing_ts;
2114 $s->last_billing_note($b->note);
2115 $s->last_billing_ts($b->billing_ts);
2116 $s->last_billing_type($b->billing_type);
2120 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2124 for my $p (@{ $x->payments }) {
2125 next if ($U->is_true($p->voided));
2126 $tp += ($p->amount * 100);
2127 $lp ||= $p->payment_ts;
2128 if ($p->payment_ts ge $lp) {
2129 $lp = $p->payment_ts;
2130 $s->last_payment_note($p->note);
2131 $s->last_payment_ts($p->payment_ts);
2132 $s->last_payment_type($p->payment_type);
2135 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2137 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2139 $s->xact_type( 'grocery' ) if ($x->grocery);
2140 $s->xact_type( 'circulation' ) if ($x->circulation);
2149 sub user_transaction_history {
2150 my( $self, $conn, $auth, $userid, $type ) = @_;
2152 # run inside of a transaction to prevent replication delays
2153 my $e = new_editor(xact=>1, authtoken=>$auth);
2154 return $e->die_event unless $e->checkauth;
2156 if( $e->requestor->id ne $userid ) {
2157 return $e->die_event
2158 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2161 my $api = $self->api_name;
2162 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2164 my @xacts = @{ $e->search_money_billable_transaction(
2165 [ { usr => $userid, @xact_finish },
2167 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2168 order_by => { mbt => 'xact_start DESC' },
2176 #my @mbts = _make_mbts( @xacts );
2177 my @mbts = $U->make_mbts( @xacts );
2179 if(defined($type)) {
2180 @mbts = grep { $_->xact_type eq $type } @mbts;
2183 if($api =~ /have_balance/o) {
2184 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2187 if($api =~ /have_charge/o) {
2188 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2191 if($api =~ /have_bill/o) {
2192 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2200 __PACKAGE__->register_method(
2201 method => "user_perms",
2202 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2204 notes => <<" NOTES");
2205 Returns a list of permissions
2208 my( $self, $client, $authtoken, $user ) = @_;
2210 my( $staff, $evt ) = $apputils->checkses($authtoken);
2211 return $evt if $evt;
2213 $user ||= $staff->id;
2215 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2219 return $apputils->simple_scalar_request(
2221 "open-ils.storage.permission.user_perms.atomic",
2225 __PACKAGE__->register_method(
2226 method => "retrieve_perms",
2227 api_name => "open-ils.actor.permissions.retrieve",
2228 notes => <<" NOTES");
2229 Returns a list of permissions
2231 sub retrieve_perms {
2232 my( $self, $client ) = @_;
2233 return $apputils->simple_scalar_request(
2235 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2236 { id => { '!=' => undef } }
2240 __PACKAGE__->register_method(
2241 method => "retrieve_groups",
2242 api_name => "open-ils.actor.groups.retrieve",
2243 notes => <<" NOTES");
2244 Returns a list of user groupss
2246 sub retrieve_groups {
2247 my( $self, $client ) = @_;
2248 return new_editor()->retrieve_all_permission_grp_tree();
2251 __PACKAGE__->register_method(
2252 method => "retrieve_org_address",
2253 api_name => "open-ils.actor.org_unit.address.retrieve",
2254 notes => <<' NOTES');
2255 Returns an org_unit address by ID
2256 @param An org_address ID
2258 sub retrieve_org_address {
2259 my( $self, $client, $id ) = @_;
2260 return $apputils->simple_scalar_request(
2262 "open-ils.cstore.direct.actor.org_address.retrieve",
2267 __PACKAGE__->register_method(
2268 method => "retrieve_groups_tree",
2269 api_name => "open-ils.actor.groups.tree.retrieve",
2270 notes => <<" NOTES");
2271 Returns a list of user groups
2273 sub retrieve_groups_tree {
2274 my( $self, $client ) = @_;
2275 return new_editor()->search_permission_grp_tree(
2280 flesh_fields => { pgt => ["children"] },
2281 order_by => { pgt => 'name'}
2288 # turns an org list into an org tree
2290 sub build_group_tree {
2292 my( $self, $grplist) = @_;
2294 return $grplist unless (
2295 ref($grplist) and @$grplist > 1 );
2297 my @list = sort { $a->name cmp $b->name } @$grplist;
2300 for my $grp (@list) {
2302 if ($grp and !defined($grp->parent)) {
2306 my ($parent) = grep { $_->id == $grp->parent} @list;
2308 $parent->children([]) unless defined($parent->children);
2309 push( @{$parent->children}, $grp );
2317 __PACKAGE__->register_method(
2318 method => "add_user_to_groups",
2319 api_name => "open-ils.actor.user.set_groups",
2320 notes => <<" NOTES");
2321 Adds a user to one or more permission groups
2324 sub add_user_to_groups {
2325 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2327 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2328 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2329 return $evt if $evt;
2331 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2332 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2333 return $evt if $evt;
2335 $apputils->simplereq(
2337 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2339 for my $group (@$groups) {
2340 my $link = Fieldmapper::permission::usr_grp_map->new;
2342 $link->usr($userid);
2344 my $id = $apputils->simplereq(
2346 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2352 __PACKAGE__->register_method(
2353 method => "get_user_perm_groups",
2354 api_name => "open-ils.actor.user.get_groups",
2355 notes => <<" NOTES");
2356 Retrieve a user's permission groups.
2360 sub get_user_perm_groups {
2361 my( $self, $client, $authtoken, $userid ) = @_;
2363 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2364 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2365 return $evt if $evt;
2367 return $apputils->simplereq(
2369 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2373 __PACKAGE__->register_method(
2374 method => "get_user_work_ous",
2375 api_name => "open-ils.actor.user.get_work_ous",
2376 notes => <<" NOTES");
2377 Retrieve a user's work org units.
2379 __PACKAGE__->register_method(
2380 method => "get_user_work_ous",
2381 api_name => "open-ils.actor.user.get_work_ous.ids",
2382 notes => <<" NOTES");
2383 Retrieve a user's work org units.
2387 sub get_user_work_ous {
2388 my( $self, $client, $auth, $userid ) = @_;
2389 my $e = new_editor(authtoken=>$auth);
2390 return $e->event unless $e->checkauth;
2391 $userid ||= $e->requestor->id;
2393 if($e->requestor->id != $userid) {
2394 my $user = $e->retrieve_actor_user($userid)
2395 or return $e->event;
2396 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2399 return $e->search_permission_usr_work_ou_map({usr => $userid})
2400 unless $self->api_name =~ /.ids$/;
2402 # client just wants a list of org IDs
2403 return $U->get_user_work_ou_ids($e, $userid);
2409 __PACKAGE__->register_method (
2410 method => 'register_workstation',
2411 api_name => 'open-ils.actor.workstation.register.override',
2412 signature => q/@see open-ils.actor.workstation.register/);
2414 __PACKAGE__->register_method (
2415 method => 'register_workstation',
2416 api_name => 'open-ils.actor.workstation.register',
2418 Registers a new workstion in the system
2419 @param authtoken The login session key
2420 @param name The name of the workstation id
2421 @param owner The org unit that owns this workstation
2422 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2423 if the name is already in use.
2426 sub register_workstation {
2427 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2429 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2430 return $e->die_event unless $e->checkauth;
2431 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2432 my $existing = $e->search_actor_workstation({name => $name})->[0];
2436 if( $self->api_name =~ /override/o ) {
2437 # workstation with the given name exists.
2439 if($owner ne $existing->owning_lib) {
2440 # if necessary, update the owning_lib of the workstation
2442 $logger->info("changing owning lib of workstation ".$existing->id.
2443 " from ".$existing->owning_lib." to $owner");
2444 return $e->die_event unless
2445 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2447 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2449 $existing->owning_lib($owner);
2450 return $e->die_event unless $e->update_actor_workstation($existing);
2456 "attempt to register an existing workstation. returning existing ID");
2459 return $existing->id;
2462 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2466 my $ws = Fieldmapper::actor::workstation->new;
2467 $ws->owning_lib($owner);
2469 $e->create_actor_workstation($ws) or return $e->die_event;
2471 return $ws->id; # note: editor sets the id on the new object for us
2474 __PACKAGE__->register_method (
2475 method => 'workstation_list',
2476 api_name => 'open-ils.actor.workstation.list',
2478 Returns a list of workstations registered at the given location
2479 @param authtoken The login session key
2480 @param ids A list of org_unit.id's for the workstation owners
2483 sub workstation_list {
2484 my( $self, $conn, $authtoken, @orgs ) = @_;
2486 my $e = new_editor(authtoken=>$authtoken);
2487 return $e->event unless $e->checkauth;
2492 unless $e->allowed('REGISTER_WORKSTATION', $o);
2493 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2504 __PACKAGE__->register_method (
2505 method => 'fetch_patron_note',
2506 api_name => 'open-ils.actor.note.retrieve.all',
2509 Returns a list of notes for a given user
2510 Requestor must have VIEW_USER permission if pub==false and
2511 @param authtoken The login session key
2512 @param args Hash of params including
2513 patronid : the patron's id
2514 pub : true if retrieving only public notes
2518 sub fetch_patron_note {
2519 my( $self, $conn, $authtoken, $args ) = @_;
2520 my $patronid = $$args{patronid};
2522 my($reqr, $evt) = $U->checkses($authtoken);
2523 return $evt if $evt;
2526 ($patron, $evt) = $U->fetch_user($patronid);
2527 return $evt if $evt;
2530 if( $patronid ne $reqr->id ) {
2531 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2532 return $evt if $evt;
2534 return $U->cstorereq(
2535 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2536 { usr => $patronid, pub => 't' } );
2539 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2540 return $evt if $evt;
2542 return $U->cstorereq(
2543 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2546 __PACKAGE__->register_method (
2547 method => 'create_user_note',
2548 api_name => 'open-ils.actor.note.create',
2550 Creates a new note for the given user
2551 @param authtoken The login session key
2552 @param note The note object
2555 sub create_user_note {
2556 my( $self, $conn, $authtoken, $note ) = @_;
2557 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2558 return $e->die_event unless $e->checkauth;
2560 my $user = $e->retrieve_actor_user($note->usr)
2561 or return $e->die_event;
2563 return $e->die_event unless
2564 $e->allowed('UPDATE_USER',$user->home_ou);
2566 $note->creator($e->requestor->id);
2567 $e->create_actor_usr_note($note) or return $e->die_event;
2573 __PACKAGE__->register_method (
2574 method => 'delete_user_note',
2575 api_name => 'open-ils.actor.note.delete',
2577 Deletes a note for the given user
2578 @param authtoken The login session key
2579 @param noteid The note id
2582 sub delete_user_note {
2583 my( $self, $conn, $authtoken, $noteid ) = @_;
2585 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2586 return $e->die_event unless $e->checkauth;
2587 my $note = $e->retrieve_actor_usr_note($noteid)
2588 or return $e->die_event;
2589 my $user = $e->retrieve_actor_user($note->usr)
2590 or return $e->die_event;
2591 return $e->die_event unless
2592 $e->allowed('UPDATE_USER', $user->home_ou);
2594 $e->delete_actor_usr_note($note) or return $e->die_event;
2600 __PACKAGE__->register_method (
2601 method => 'update_user_note',
2602 api_name => 'open-ils.actor.note.update',
2604 @param authtoken The login session key
2605 @param note The note
2609 sub update_user_note {
2610 my( $self, $conn, $auth, $note ) = @_;
2611 my $e = new_editor(authtoken=>$auth, xact=>1);
2612 return $e->event unless $e->checkauth;
2613 my $patron = $e->retrieve_actor_user($note->usr)
2614 or return $e->event;
2615 return $e->event unless
2616 $e->allowed('UPDATE_USER', $patron->home_ou);
2617 $e->update_actor_user_note($note)
2618 or return $e->event;
2626 __PACKAGE__->register_method (
2627 method => 'create_closed_date',
2628 api_name => 'open-ils.actor.org_unit.closed_date.create',
2630 Creates a new closing entry for the given org_unit
2631 @param authtoken The login session key
2632 @param note The closed_date object
2635 sub create_closed_date {
2636 my( $self, $conn, $authtoken, $cd ) = @_;
2638 my( $user, $evt ) = $U->checkses($authtoken);
2639 return $evt if $evt;
2641 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2642 return $evt if $evt;
2644 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2646 my $id = $U->storagereq(
2647 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2648 return $U->DB_UPDATE_FAILED($cd) unless $id;
2653 __PACKAGE__->register_method (
2654 method => 'delete_closed_date',
2655 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2657 Deletes a closing entry for the given org_unit
2658 @param authtoken The login session key
2659 @param noteid The close_date id
2662 sub delete_closed_date {
2663 my( $self, $conn, $authtoken, $cd ) = @_;
2665 my( $user, $evt ) = $U->checkses($authtoken);
2666 return $evt if $evt;
2669 ($cd_obj, $evt) = fetch_closed_date($cd);
2670 return $evt if $evt;
2672 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2673 return $evt if $evt;
2675 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2677 my $stat = $U->storagereq(
2678 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2679 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2684 __PACKAGE__->register_method(
2685 method => 'usrname_exists',
2686 api_name => 'open-ils.actor.username.exists',
2688 Returns 1 if the requested username exists, returns 0 otherwise
2692 sub usrname_exists {
2693 my( $self, $conn, $auth, $usrname ) = @_;
2694 my $e = new_editor(authtoken=>$auth);
2695 return $e->event unless $e->checkauth;
2696 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2697 return $$a[0] if $a and @$a;
2701 __PACKAGE__->register_method(
2702 method => 'barcode_exists',
2703 api_name => 'open-ils.actor.barcode.exists',
2706 Returns 1 if the requested barcode exists, returns 0 otherwise
2710 sub barcode_exists {
2711 my( $self, $conn, $auth, $barcode ) = @_;
2712 my $e = new_editor(authtoken=>$auth);
2713 return $e->event unless $e->checkauth;
2714 my $card = $e->search_actor_card({barcode => $barcode});
2715 return undef unless @$card;
2716 return $card->[0]->usr;
2720 __PACKAGE__->register_method(
2721 method => 'retrieve_net_levels',
2722 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2725 sub retrieve_net_levels {
2726 my( $self, $conn, $auth ) = @_;
2727 my $e = new_editor(authtoken=>$auth);
2728 return $e->event unless $e->checkauth;
2729 return $e->retrieve_all_config_net_access_level();
2733 __PACKAGE__->register_method(
2734 method => 'fetch_org_by_shortname',
2735 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2737 sub fetch_org_by_shortname {
2738 my( $self, $conn, $sname ) = @_;
2739 my $e = new_editor();
2740 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2741 return $e->event unless $org;
2746 __PACKAGE__->register_method(
2747 method => 'session_home_lib',
2748 api_name => 'open-ils.actor.session.home_lib',
2751 sub session_home_lib {
2752 my( $self, $conn, $auth ) = @_;
2753 my $e = new_editor(authtoken=>$auth);
2754 return undef unless $e->checkauth;
2755 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2756 return $org->shortname;
2759 __PACKAGE__->register_method(
2760 method => 'session_safe_token',
2761 api_name => 'open-ils.actor.session.safe_token',
2763 Returns a hashed session ID that is safe for export to the world.
2764 This safe token will expire after 1 hour of non-use.
2765 @param auth Active authentication token
2769 sub session_safe_token {
2770 my( $self, $conn, $auth ) = @_;
2771 my $e = new_editor(authtoken=>$auth);
2772 return undef unless $e->checkauth;
2774 my $safe_token = md5_hex($auth);
2776 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2778 # Add more like the following if needed...
2780 "safe-token-home_lib-shortname-$safe_token",
2781 $e->retrieve_actor_org_unit(
2782 $e->requestor->home_ou
2791 __PACKAGE__->register_method(
2792 method => 'safe_token_home_lib',
2793 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2795 Returns the home library shortname from the session
2796 asscociated with a safe token from generated by
2797 open-ils.actor.session.safe_token.
2798 @param safe_token Active safe token
2802 sub safe_token_home_lib {
2803 my( $self, $conn, $safe_token ) = @_;
2805 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2806 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2811 __PACKAGE__->register_method(
2812 method => 'slim_tree',
2813 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2816 my $tree = new_editor()->search_actor_org_unit(
2818 {"parent_ou" => undef },
2821 flesh_fields => { aou => ['children'] },
2822 order_by => { aou => 'name'},
2823 select => { aou => ["id","shortname", "name"]},
2828 return trim_tree($tree);
2834 return undef unless $tree;
2836 code => $tree->shortname,
2837 name => $tree->name,
2839 if( $tree->children and @{$tree->children} ) {
2840 $htree->{children} = [];
2841 for my $c (@{$tree->children}) {
2842 push( @{$htree->{children}}, trim_tree($c) );
2850 __PACKAGE__->register_method(
2851 method => "update_penalties",
2852 api_name => "open-ils.actor.user.penalties.update");
2853 sub update_penalties {
2854 my( $self, $conn, $auth, $userid ) = @_;
2855 my $e = new_editor(authtoken=>$auth);
2856 return $e->event unless $e->checkauth;
2857 $U->update_patron_penalties(
2859 patronid => $userid,
2866 __PACKAGE__->register_method(
2867 method => "user_retrieve_fleshed_by_id",
2868 api_name => "open-ils.actor.user.fleshed.retrieve",);
2870 sub user_retrieve_fleshed_by_id {
2871 my( $self, $client, $auth, $user_id, $fields ) = @_;
2872 my $e = new_editor(authtoken => $auth);
2873 return $e->event unless $e->checkauth;
2875 if( $e->requestor->id != $user_id ) {
2876 return $e->event unless $e->allowed('VIEW_USER');
2882 "standing_penalties",
2886 "stat_cat_entries" ];
2887 return new_flesh_user($user_id, $fields, $e);
2891 sub new_flesh_user {
2894 my $fields = shift || [];
2895 my $e = shift || new_editor(xact=>1);
2897 my $user = $e->retrieve_actor_user(
2902 "flesh_fields" => { "au" => $fields }
2905 ) or return $e->event;
2908 if( grep { $_ eq 'addresses' } @$fields ) {
2910 $user->addresses([]) unless @{$user->addresses};
2912 if( ref $user->billing_address ) {
2913 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2914 push( @{$user->addresses}, $user->billing_address );
2918 if( ref $user->mailing_address ) {
2919 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2920 push( @{$user->addresses}, $user->mailing_address );
2926 $user->clear_passwd();
2933 __PACKAGE__->register_method(
2934 method => "user_retrieve_parts",
2935 api_name => "open-ils.actor.user.retrieve.parts",);
2937 sub user_retrieve_parts {
2938 my( $self, $client, $auth, $user_id, $fields ) = @_;
2939 my $e = new_editor(authtoken => $auth);
2940 return $e->event unless $e->checkauth;
2941 if( $e->requestor->id != $user_id ) {
2942 return $e->event unless $e->allowed('VIEW_USER');
2945 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2946 push(@resp, $user->$_()) for(@$fields);
2952 __PACKAGE__->register_method(
2953 method => 'user_opt_in_enabled',
2954 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2956 @return 1 if user opt-in is globally enabled, 0 otherwise.
2959 sub user_opt_in_enabled {
2960 my($self, $conn) = @_;
2961 my $sc = OpenSRF::Utils::SettingsClient->new;
2962 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2967 __PACKAGE__->register_method(
2968 method => 'user_opt_in_at_org',
2969 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2971 @param $auth The auth token
2972 @param user_id The ID of the user to test
2973 @return 1 if the user has opted in at the specified org,
2974 event on error, and 0 otherwise. /);
2975 sub user_opt_in_at_org {
2976 my($self, $conn, $auth, $user_id) = @_;
2978 # see if we even need to enforce the opt-in value
2979 return 1 unless user_opt_in_enabled($self);
2981 my $e = new_editor(authtoken => $auth);
2982 return $e->event unless $e->checkauth;
2983 my $org_id = $e->requestor->ws_ou;
2985 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2986 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
2988 # user is automatically opted-in at the home org
2989 return 1 if $user->home_ou eq $org_id;
2991 my $vals = $e->search_actor_usr_org_unit_opt_in(
2992 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
2998 __PACKAGE__->register_method(
2999 method => 'create_user_opt_in_at_org',
3000 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3002 @param $auth The auth token
3003 @param user_id The ID of the user to test
3004 @return The ID of the newly created object, event on error./);
3006 sub create_user_opt_in_at_org {
3007 my($self, $conn, $auth, $user_id) = @_;
3009 my $e = new_editor(authtoken => $auth, xact=>1);
3010 return $e->die_event unless $e->checkauth;
3011 my $org_id = $e->requestor->ws_ou;
3013 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3014 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3016 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3018 $opt_in->org_unit($org_id);
3019 $opt_in->usr($user_id);
3020 $opt_in->staff($e->requestor->id);
3021 $opt_in->opt_in_ts('now');
3022 $opt_in->opt_in_ws($e->requestor->wsid);
3024 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3025 or return $e->die_event;