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);
82 __PACKAGE__->register_method(
83 method => "set_ou_settings",
84 api_name => "open-ils.actor.org_unit.settings.update",
87 my( $self, $client, $user_session, $ouid, $settings ) = @_;
89 my( $staff, $evt ) = $apputils->checkses( $user_session );
91 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
95 for my $set (keys %$settings) {
97 my $json = OpenSRF::Utils::JSON->perl2JSON($$settings{$set});
98 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
101 { org_unit => $ouid, name => $set },
102 { value => $json } );
105 my $ses = $U->start_db_session();
106 my $stat = $ses->request(
107 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
108 $U->commit_db_session($ses);
114 my $fetch_user_settings;
115 my $fetch_ou_settings;
117 __PACKAGE__->register_method(
118 method => "user_settings",
119 api_name => "open-ils.actor.patron.settings.retrieve",
122 my( $self, $client, $user_session, $uid, $setting ) = @_;
124 my( $staff, $user, $evt ) =
125 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
128 $logger->debug("User " . $staff->id . " fetching user $uid\n");
129 my $s = $apputils->simplereq(
131 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
133 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
135 return $$settings{$setting} if $setting;
141 __PACKAGE__->register_method(
142 method => "ou_settings",
143 api_name => "open-ils.actor.org_unit.settings.retrieve",
146 my( $self, $client, $ouid ) = @_;
148 $logger->info("Fetching org unit settings for org $ouid");
150 my $s = $apputils->simplereq(
152 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
154 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
159 __PACKAGE__->register_method(
160 api_name => 'open-ils.actor.ou_setting.ancestor_default',
161 method => 'ou_ancestor_setting',
164 # ------------------------------------------------------------------
165 # Attempts to find the org setting value for a given org. if not
166 # found at the requested org, searches up the org tree until it
167 # finds a parent that has the requested setting.
168 # when found, returns { org => $id, value => $value }
169 # otherwise, returns NULL
170 # ------------------------------------------------------------------
171 sub ou_ancestor_setting {
172 my( $self, $client, $orgid, $name ) = @_;
173 return $U->ou_ancestor_setting($orgid, $name);
179 __PACKAGE__->register_method (
180 method => "ou_setting_delete",
181 api_name => 'open-ils.actor.org_setting.delete',
183 Deletes a specific org unit setting for a specific location
184 @param authtoken The login session key
185 @param orgid The org unit whose setting we're changing
186 @param setting The name of the setting to delete
187 @return True value on success.
191 sub ou_setting_delete {
192 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
193 my( $reqr, $evt) = $U->checkses($authtoken);
195 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
198 my $id = $U->cstorereq(
199 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
200 { name => $setting, org_unit => $orgid } );
202 $logger->debug("Retrieved setting $id in org unit setting delete");
204 my $s = $U->cstorereq(
205 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
207 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
221 __PACKAGE__->register_method(
222 method => "update_patron",
223 api_name => "open-ils.actor.patron.update",);
226 my( $self, $client, $user_session, $patron ) = @_;
228 my $session = $apputils->start_db_session();
232 $logger->info("Creating new patron...") if $patron->isnew;
233 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
235 my( $user_obj, $evt ) = $U->checkses($user_session);
238 $evt = check_group_perm($session, $user_obj, $patron);
242 # $new_patron is the patron in progress. $patron is the original patron
243 # passed in with the method. new_patron will change as the components
244 # of patron are added/updated.
248 # unflesh the real items on the patron
249 $patron->card( $patron->card->id ) if(ref($patron->card));
250 $patron->billing_address( $patron->billing_address->id )
251 if(ref($patron->billing_address));
252 $patron->mailing_address( $patron->mailing_address->id )
253 if(ref($patron->mailing_address));
255 # create/update the patron first so we can use his id
256 if($patron->isnew()) {
257 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
259 } else { $new_patron = $patron; }
261 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
264 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
267 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
270 # re-update the patron if anything has happened to him during this process
271 if($new_patron->ischanged()) {
272 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
276 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
279 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
282 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
285 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
288 if(!$patron->isnew) {
289 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
292 $apputils->commit_db_session($session);
293 my $fuser = flesh_user($new_patron->id());
296 # Log the new and old patron for investigation
297 $logger->info("$user_session updating patron object. orig patron object = ".
298 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
308 return new_flesh_user($id, [
311 "standing_penalties",
315 "stat_cat_entries" ] );
323 # clone and clear stuff that would break the database
327 my $new_patron = $patron->clone;
329 $new_patron->clear_billing_address();
330 $new_patron->clear_mailing_address();
331 $new_patron->clear_addresses();
332 $new_patron->clear_card();
333 $new_patron->clear_cards();
334 $new_patron->clear_id();
335 $new_patron->clear_isnew();
336 $new_patron->clear_ischanged();
337 $new_patron->clear_isdeleted();
338 $new_patron->clear_stat_cat_entries();
339 $new_patron->clear_permissions();
340 $new_patron->clear_standing_penalties();
350 my $user_obj = shift;
352 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
353 return (undef, $evt) if $evt;
355 my $ex = $session->request(
356 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
358 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
361 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
363 my $id = $session->request(
364 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
365 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
367 $logger->info("Successfully created new user [$id] in DB");
369 return ( $session->request(
370 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
374 sub check_group_perm {
375 my( $session, $requestor, $patron ) = @_;
378 # first let's see if the requestor has
379 # priveleges to update this user in any way
380 if( ! $patron->isnew ) {
381 my $p = $session->request(
382 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
384 # If we are the requestor (trying to update our own account)
385 # and we are not trying to change our profile, we're good
386 if( $p->id == $requestor->id and
387 $p->profile == $patron->profile ) {
392 $evt = group_perm_failed($session, $requestor, $p);
396 # They are allowed to edit this patron.. can they put the
397 # patron into the group requested?
398 $evt = group_perm_failed($session, $requestor, $patron);
404 sub group_perm_failed {
405 my( $session, $requestor, $patron ) = @_;
409 my $grpid = $patron->profile;
413 $logger->debug("user update looking for group perm for group $grpid");
414 $grp = $session->request(
415 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
416 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
418 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
420 $logger->info("user update checking perm $perm on user ".
421 $requestor->id." for update/create on user username=".$patron->usrname);
423 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
431 my( $session, $patron, $user_obj, $noperm) = @_;
433 $logger->info("Updating patron ".$patron->id." in DB");
438 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
439 return (undef, $evt) if $evt;
442 # update the password by itself to avoid the password protection magic
443 if( $patron->passwd ) {
444 my $s = $session->request(
445 'open-ils.storage.direct.actor.user.remote_update',
446 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
447 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
448 $patron->clear_passwd;
451 if(!$patron->ident_type) {
452 $patron->clear_ident_type;
453 $patron->clear_ident_value;
456 $evt = verify_last_xact($session, $patron);
457 return (undef, $evt) if $evt;
459 my $stat = $session->request(
460 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
461 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
466 sub verify_last_xact {
467 my( $session, $patron ) = @_;
468 return undef unless $patron->id and $patron->id > 0;
469 my $p = $session->request(
470 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
471 my $xact = $p->last_xact_id;
472 return undef unless $xact;
473 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
474 return OpenILS::Event->new('XACT_COLLISION')
475 if $xact != $patron->last_xact_id;
480 sub _check_dup_ident {
481 my( $session, $patron ) = @_;
483 return undef unless $patron->ident_value;
486 ident_type => $patron->ident_type,
487 ident_value => $patron->ident_value,
490 $logger->debug("patron update searching for dup ident values: " .
491 $patron->ident_type . ':' . $patron->ident_value);
493 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
495 my $dups = $session->request(
496 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
499 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
506 sub _add_update_addresses {
510 my $new_patron = shift;
514 my $current_id; # id of the address before creation
516 for my $address (@{$patron->addresses()}) {
518 next unless ref $address;
519 $current_id = $address->id();
521 if( $patron->billing_address() and
522 $patron->billing_address() == $current_id ) {
523 $logger->info("setting billing addr to $current_id");
524 $new_patron->billing_address($address->id());
525 $new_patron->ischanged(1);
528 if( $patron->mailing_address() and
529 $patron->mailing_address() == $current_id ) {
530 $new_patron->mailing_address($address->id());
531 $logger->info("setting mailing addr to $current_id");
532 $new_patron->ischanged(1);
536 if($address->isnew()) {
538 $address->usr($new_patron->id());
540 ($address, $evt) = _add_address($session,$address);
541 return (undef, $evt) if $evt;
543 # we need to get the new id
544 if( $patron->billing_address() and
545 $patron->billing_address() == $current_id ) {
546 $new_patron->billing_address($address->id());
547 $logger->info("setting billing addr to $current_id");
548 $new_patron->ischanged(1);
551 if( $patron->mailing_address() and
552 $patron->mailing_address() == $current_id ) {
553 $new_patron->mailing_address($address->id());
554 $logger->info("setting mailing addr to $current_id");
555 $new_patron->ischanged(1);
558 } elsif($address->ischanged() ) {
560 ($address, $evt) = _update_address($session, $address);
561 return (undef, $evt) if $evt;
563 } elsif($address->isdeleted() ) {
565 if( $address->id() == $new_patron->mailing_address() ) {
566 $new_patron->clear_mailing_address();
567 ($new_patron, $evt) = _update_patron($session, $new_patron);
568 return (undef, $evt) if $evt;
571 if( $address->id() == $new_patron->billing_address() ) {
572 $new_patron->clear_billing_address();
573 ($new_patron, $evt) = _update_patron($session, $new_patron);
574 return (undef, $evt) if $evt;
577 $evt = _delete_address($session, $address);
578 return (undef, $evt) if $evt;
582 return ( $new_patron, undef );
586 # adds an address to the db and returns the address with new id
588 my($session, $address) = @_;
589 $address->clear_id();
591 $logger->info("Creating new address at street ".$address->street1);
593 # put the address into the database
594 my $id = $session->request(
595 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
596 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
599 return ($address, undef);
603 sub _update_address {
604 my( $session, $address ) = @_;
606 $logger->info("Updating address ".$address->id." in the DB");
608 my $stat = $session->request(
609 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
611 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
612 return ($address, undef);
617 sub _add_update_cards {
621 my $new_patron = shift;
625 my $virtual_id; #id of the card before creation
626 for my $card (@{$patron->cards()}) {
628 $card->usr($new_patron->id());
630 if(ref($card) and $card->isnew()) {
632 $virtual_id = $card->id();
633 ( $card, $evt ) = _add_card($session,$card);
634 return (undef, $evt) if $evt;
636 #if(ref($patron->card)) { $patron->card($patron->card->id); }
637 if($patron->card() == $virtual_id) {
638 $new_patron->card($card->id());
639 $new_patron->ischanged(1);
642 } elsif( ref($card) and $card->ischanged() ) {
643 $evt = _update_card($session, $card);
644 return (undef, $evt) if $evt;
648 return ( $new_patron, undef );
652 # adds an card to the db and returns the card with new id
654 my( $session, $card ) = @_;
657 $logger->info("Adding new patron card ".$card->barcode);
659 my $id = $session->request(
660 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
661 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
662 $logger->info("Successfully created patron card $id");
665 return ( $card, undef );
669 # returns event on error. returns undef otherwise
671 my( $session, $card ) = @_;
672 $logger->info("Updating patron card ".$card->id);
674 my $stat = $session->request(
675 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
676 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
683 # returns event on error. returns undef otherwise
684 sub _delete_address {
685 my( $session, $address ) = @_;
687 $logger->info("Deleting address ".$address->id." from DB");
689 my $stat = $session->request(
690 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
692 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
698 sub _add_survey_responses {
699 my ($session, $patron, $new_patron) = @_;
701 $logger->info( "Updating survey responses for patron ".$new_patron->id );
703 my $responses = $patron->survey_responses;
707 $_->usr($new_patron->id) for (@$responses);
709 my $evt = $U->simplereq( "open-ils.circ",
710 "open-ils.circ.survey.submit.user_id", $responses );
712 return (undef, $evt) if defined($U->event_code($evt));
716 return ( $new_patron, undef );
720 sub _create_stat_maps {
722 my($session, $user_session, $patron, $new_patron) = @_;
724 my $maps = $patron->stat_cat_entries();
726 for my $map (@$maps) {
728 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
730 if ($map->isdeleted()) {
731 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
733 } elsif ($map->isnew()) {
734 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
739 $map->target_usr($new_patron->id);
742 $logger->info("Updating stat entry with method $method and map $map");
744 my $stat = $session->request($method, $map)->gather(1);
745 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
749 return ($new_patron, undef);
752 sub _create_perm_maps {
754 my($session, $user_session, $patron, $new_patron) = @_;
756 my $maps = $patron->permissions;
758 for my $map (@$maps) {
760 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
761 if ($map->isdeleted()) {
762 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
763 } elsif ($map->isnew()) {
764 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
769 $map->usr($new_patron->id);
771 #warn( "Updating permissions with method $method and session $user_session and map $map" );
772 $logger->info( "Updating permissions with method $method and map $map" );
774 my $stat = $session->request($method, $map)->gather(1);
775 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
779 return ($new_patron, undef);
783 __PACKAGE__->register_method(
784 method => "set_user_work_ous",
785 api_name => "open-ils.actor.user.work_ous.update",
788 sub set_user_work_ous {
794 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
797 my $session = $apputils->start_db_session();
799 for my $map (@$maps) {
801 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
802 if ($map->isdeleted()) {
803 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
804 } elsif ($map->isnew()) {
805 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
809 #warn( "Updating permissions with method $method and session $ses and map $map" );
810 $logger->info( "Updating work_ou map with method $method and map $map" );
812 my $stat = $session->request($method, $map)->gather(1);
813 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
817 $apputils->commit_db_session($session);
819 return scalar(@$maps);
823 __PACKAGE__->register_method(
824 method => "set_user_perms",
825 api_name => "open-ils.actor.user.permissions.update",
834 my $session = $apputils->start_db_session();
836 my( $user_obj, $evt ) = $U->checkses($ses);
839 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
842 $all = 1 if ($user_obj->super_user());
843 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
845 for my $map (@$maps) {
847 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
848 if ($map->isdeleted()) {
849 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
850 } elsif ($map->isnew()) {
851 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
855 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
857 #warn( "Updating permissions with method $method and session $ses and map $map" );
858 $logger->info( "Updating permissions with method $method and map $map" );
860 my $stat = $session->request($method, $map)->gather(1);
861 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
865 $apputils->commit_db_session($session);
867 return scalar(@$maps);
871 sub _create_standing_penalties {
873 my($session, $user_session, $patron, $new_patron) = @_;
875 my $maps = $patron->standing_penalties;
878 for my $map (@$maps) {
880 if ($map->isdeleted()) {
881 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
882 } elsif ($map->isnew()) {
883 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
889 $map->usr($new_patron->id);
891 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
893 my $stat = $session->request($method, $map)->gather(1);
894 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
897 return ($new_patron, undef);
902 __PACKAGE__->register_method(
903 method => "search_username",
904 api_name => "open-ils.actor.user.search.username",
907 sub search_username {
908 my($self, $client, $username) = @_;
909 return new_editor()->search_actor_user({usrname=>$username});
915 __PACKAGE__->register_method(
916 method => "user_retrieve_by_barcode",
917 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
919 sub user_retrieve_by_barcode {
920 my($self, $client, $user_session, $barcode) = @_;
922 $logger->debug("Searching for user with barcode $barcode");
923 my ($user_obj, $evt) = $apputils->checkses($user_session);
926 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
928 "open-ils.cstore.direct.actor.card.search.atomic",
929 { barcode => $barcode }
932 if(!$card || !$card->[0]) {
933 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
937 my $user = flesh_user($card->usr());
939 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
942 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
949 __PACKAGE__->register_method(
950 method => "get_user_by_id",
951 api_name => "open-ils.actor.user.retrieve",);
954 my ($self, $client, $auth, $id) = @_;
955 my $e = new_editor(authtoken=>$auth);
956 return $e->event unless $e->checkauth;
957 my $user = $e->retrieve_actor_user($id)
959 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
965 __PACKAGE__->register_method(
966 method => "get_org_types",
967 api_name => "open-ils.actor.org_types.retrieve",);
971 my($self, $client) = @_;
972 return $org_types if $org_types;
973 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
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",
1037 my( $self, $client) = @_;
1039 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
1040 my $tree = $cache->get_cache('orgtree');
1041 return $tree if $tree;
1043 $tree = new_editor()->search_actor_org_unit(
1045 {"parent_ou" => undef },
1048 flesh_fields => { aou => ['children'] },
1049 order_by => { aou => 'name'}
1054 $cache->put_cache('orgtree', $tree);
1059 # turns an org list into an org tree
1060 sub build_org_tree {
1062 my( $self, $orglist) = @_;
1064 return $orglist unless ref $orglist;
1065 return $$orglist[0] if @$orglist == 1;
1068 $a->ou_type <=> $b->ou_type ||
1069 $a->name cmp $b->name } @$orglist;
1071 for my $org (@list) {
1073 next unless ($org and defined($org->parent_ou));
1074 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1075 next unless $parent;
1077 $parent->children([]) unless defined($parent->children);
1078 push( @{$parent->children}, $org );
1086 __PACKAGE__->register_method(
1087 method => "get_org_descendants",
1088 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1091 # depth is optional. org_unit is the id
1092 sub get_org_descendants {
1093 my( $self, $client, $org_unit, $depth ) = @_;
1094 my $orglist = $apputils->simple_scalar_request(
1096 "open-ils.storage.actor.org_unit.descendants.atomic",
1097 $org_unit, $depth );
1098 return $self->build_org_tree($orglist);
1102 __PACKAGE__->register_method(
1103 method => "get_org_ancestors",
1104 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1107 # depth is optional. org_unit is the id
1108 sub get_org_ancestors {
1109 my( $self, $client, $org_unit, $depth ) = @_;
1110 my $orglist = $apputils->simple_scalar_request(
1112 "open-ils.storage.actor.org_unit.ancestors.atomic",
1113 $org_unit, $depth );
1114 return $self->build_org_tree($orglist);
1118 __PACKAGE__->register_method(
1119 method => "get_standings",
1120 api_name => "open-ils.actor.standings.retrieve"
1125 return $user_standings if $user_standings;
1126 return $user_standings =
1127 $apputils->simple_scalar_request(
1129 "open-ils.cstore.direct.config.standing.search.atomic",
1130 { id => { "!=" => undef } }
1136 __PACKAGE__->register_method(
1137 method => "get_my_org_path",
1138 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1141 sub get_my_org_path {
1142 my( $self, $client, $auth, $org_id ) = @_;
1143 my $e = new_editor(authtoken=>$auth);
1144 return $e->event unless $e->checkauth;
1145 $org_id = $e->requestor->ws_ou unless defined $org_id;
1147 return $apputils->simple_scalar_request(
1149 "open-ils.storage.actor.org_unit.full_path.atomic",
1154 __PACKAGE__->register_method(
1155 method => "patron_adv_search",
1156 api_name => "open-ils.actor.patron.search.advanced" );
1157 sub patron_adv_search {
1158 my( $self, $client, $auth, $search_hash,
1159 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1161 my $e = new_editor(authtoken=>$auth);
1162 return $e->event unless $e->checkauth;
1163 return $e->event unless $e->allowed('VIEW_USER');
1164 return $U->storagereq(
1165 "open-ils.storage.actor.user.crazy_search", $search_hash,
1166 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1172 sub _verify_password {
1173 my($user_session, $password) = @_;
1174 my $user_obj = $apputils->check_user_session($user_session);
1176 #grab the user with password
1177 $user_obj = $apputils->simple_scalar_request(
1179 "open-ils.cstore.direct.actor.user.retrieve",
1182 if($user_obj->passwd eq $password) {
1190 __PACKAGE__->register_method(
1191 method => "update_password",
1192 api_name => "open-ils.actor.user.password.update");
1194 __PACKAGE__->register_method(
1195 method => "update_password",
1196 api_name => "open-ils.actor.user.username.update");
1198 __PACKAGE__->register_method(
1199 method => "update_password",
1200 api_name => "open-ils.actor.user.email.update");
1202 sub update_password {
1203 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1207 my $session = $apputils->start_db_session();
1208 my $user_obj = $apputils->check_user_session($user_session);
1210 #fetch the in-database version so we get the latest xact_id
1211 $user_obj = $session->request(
1212 'open-ils.storage.direct.actor.user.retrieve', $user_obj->id)->gather(1);
1214 if($self->api_name =~ /password/o) {
1216 #make sure they know the current password
1217 if(!_verify_password($user_session, md5_hex($current_password))) {
1218 return OpenILS::Event->new('INCORRECT_PASSWORD');
1221 $logger->debug("update_password setting new password $new_value");
1222 $user_obj->passwd($new_value);
1224 } elsif($self->api_name =~ /username/o) {
1225 my $users = search_username(undef, undef, $new_value);
1226 if( $users and $users->[0] ) {
1227 return OpenILS::Event->new('USERNAME_EXISTS');
1229 $user_obj->usrname($new_value);
1231 } elsif($self->api_name =~ /email/o) {
1232 #warn "Updating email to $new_value\n";
1233 $user_obj->email($new_value);
1237 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1238 return $evt if $evt;
1240 $apputils->commit_db_session($session);
1242 if($user_obj) { return 1; }
1247 __PACKAGE__->register_method(
1248 method => "update_passwd",
1249 api_name => "open-ils.actor.user.password.update");
1251 __PACKAGE__->register_method(
1252 method => "update_passwd",
1253 api_name => "open-ils.actor.user.username.update");
1255 __PACKAGE__->register_method(
1256 method => "update_passwd",
1257 api_name => "open-ils.actor.user.email.update");
1260 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1261 my $e = new_editor(xact=>1, authtoken=>$auth);
1262 return $e->die_event unless $e->checkauth;
1264 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1265 or return $e->die_event;
1266 my $api = $self->api_name;
1268 if( $api =~ /password/o ) {
1270 # make sure the original password matches the in-database password
1271 return OpenILS::Event->new('INCORRECT_PASSWORD')
1272 if md5_hex($orig_pw) ne $db_user->passwd;
1273 $db_user->passwd($new_val);
1277 # if we don't clear the password, the user will be updated with
1278 # a hashed version of the hashed version of their password
1279 $db_user->clear_passwd;
1281 if( $api =~ /username/o ) {
1283 # make sure no one else has this username
1284 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1285 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1286 $db_user->usrname($new_val);
1288 } elsif( $api =~ /email/o ) {
1289 $db_user->email($new_val);
1293 $e->update_actor_user($db_user) or return $e->die_event;
1301 __PACKAGE__->register_method(
1302 method => "check_user_perms",
1303 api_name => "open-ils.actor.user.perm.check",
1304 notes => <<" NOTES");
1305 Takes a login session, user id, an org id, and an array of perm type strings. For each
1306 perm type, if the user does *not* have the given permission it is added
1307 to a list which is returned from the method. If all permissions
1308 are allowed, an empty list is returned
1309 if the logged in user does not match 'user_id', then the logged in user must
1310 have VIEW_PERMISSION priveleges.
1313 sub check_user_perms {
1314 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1316 my( $staff, $evt ) = $apputils->checkses($login_session);
1317 return $evt if $evt;
1319 if($staff->id ne $user_id) {
1320 if( $evt = $apputils->check_perms(
1321 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1327 for my $perm (@$perm_types) {
1328 if($apputils->check_perms($user_id, $org_id, $perm)) {
1329 push @not_allowed, $perm;
1333 return \@not_allowed
1336 __PACKAGE__->register_method(
1337 method => "check_user_perms2",
1338 api_name => "open-ils.actor.user.perm.check.multi_org",
1340 Checks the permissions on a list of perms and orgs for a user
1341 @param authtoken The login session key
1342 @param user_id The id of the user to check
1343 @param orgs The array of org ids
1344 @param perms The array of permission names
1345 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1346 if the logged in user does not match 'user_id', then the logged in user must
1347 have VIEW_PERMISSION priveleges.
1350 sub check_user_perms2 {
1351 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1353 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1354 $authtoken, $user_id, 'VIEW_PERMISSION' );
1355 return $evt if $evt;
1358 for my $org (@$orgs) {
1359 for my $perm (@$perms) {
1360 if($apputils->check_perms($user_id, $org, $perm)) {
1361 push @not_allowed, [ $org, $perm ];
1366 return \@not_allowed
1370 __PACKAGE__->register_method(
1371 method => 'check_user_perms3',
1372 api_name => 'open-ils.actor.user.perm.highest_org',
1374 Returns the highest org unit id at which a user has a given permission
1375 If the requestor does not match the target user, the requestor must have
1376 'VIEW_PERMISSION' rights at the home org unit of the target user
1377 @param authtoken The login session key
1378 @param userid The id of the user in question
1379 @param perm The permission to check
1380 @return The org unit highest in the org tree within which the user has
1381 the requested permission
1384 sub check_user_perms3 {
1385 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1387 my( $staff, $target, $org, $evt );
1389 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1390 $authtoken, $userid, 'VIEW_PERMISSION' );
1391 return $evt if $evt;
1393 my $tree = $self->get_org_tree();
1394 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1398 sub _find_highest_perm_org {
1399 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1400 my $org = $apputils->find_org($org_tree, $start_org );
1404 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1406 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1412 __PACKAGE__->register_method(
1413 method => 'check_user_perms4',
1414 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1416 Returns the highest org unit id at which a user has a given permission
1417 If the requestor does not match the target user, the requestor must have
1418 'VIEW_PERMISSION' rights at the home org unit of the target user
1419 @param authtoken The login session key
1420 @param userid The id of the user in question
1421 @param perms An array of perm names to check
1422 @return An array of orgId's representing the org unit
1423 highest in the org tree within which the user has the requested permission
1424 The arrah of orgId's has matches the order of the perms array
1427 sub check_user_perms4 {
1428 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1430 my( $staff, $target, $org, $evt );
1432 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1433 $authtoken, $userid, 'VIEW_PERMISSION' );
1434 return $evt if $evt;
1437 return [] unless ref($perms);
1438 my $tree = $self->get_org_tree();
1440 for my $p (@$perms) {
1441 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1449 __PACKAGE__->register_method(
1450 method => "user_fines_summary",
1451 api_name => "open-ils.actor.user.fines.summary",
1452 notes => <<" NOTES");
1453 Returns a short summary of the users total open fines, excluding voided fines
1454 Params are login_session, user_id
1455 Returns a 'mous' object.
1458 sub user_fines_summary {
1459 my( $self, $client, $auth, $user_id ) = @_;
1460 my $e = new_editor(authtoken=>$auth);
1461 return $e->event unless $e->checkauth;
1462 my $user = $e->retrieve_actor_user($user_id)
1463 or return $e->event;
1465 if( $user_id ne $e->requestor->id ) {
1466 return $e->event unless
1467 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1470 # run this inside a transaction to prevent replication delay errors
1471 my $ses = $U->start_db_session();
1472 my $s = $ses->request(
1473 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1474 $U->rollback_db_session($ses);
1481 __PACKAGE__->register_method(
1482 method => "user_transactions",
1483 api_name => "open-ils.actor.user.transactions",
1484 notes => <<" NOTES");
1485 Returns a list of open user transactions (mbts objects);
1486 Params are login_session, user_id
1487 Optional third parameter is the transactions type. defaults to all
1490 __PACKAGE__->register_method(
1491 method => "user_transactions",
1492 api_name => "open-ils.actor.user.transactions.have_charge",
1493 notes => <<" NOTES");
1494 Returns a list of all open user transactions (mbts objects) that have an initial charge
1495 Params are login_session, user_id
1496 Optional third parameter is the transactions type. defaults to all
1499 __PACKAGE__->register_method(
1500 method => "user_transactions",
1501 api_name => "open-ils.actor.user.transactions.have_balance",
1502 notes => <<" NOTES");
1503 Returns a list of all open user transactions (mbts objects) that have a balance
1504 Params are login_session, user_id
1505 Optional third parameter is the transactions type. defaults to all
1508 __PACKAGE__->register_method(
1509 method => "user_transactions",
1510 api_name => "open-ils.actor.user.transactions.fleshed",
1511 notes => <<" NOTES");
1512 Returns an object/hash of transaction, circ, title where transaction = an open
1513 user transactions (mbts objects), circ is the attached circluation, and title
1514 is the title the circ points to
1515 Params are login_session, user_id
1516 Optional third parameter is the transactions type. defaults to all
1519 __PACKAGE__->register_method(
1520 method => "user_transactions",
1521 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1522 notes => <<" NOTES");
1523 Returns an object/hash of transaction, circ, title where transaction = an open
1524 user transactions that has an initial charge (mbts objects), circ is the
1525 attached circluation, and title is the title the circ points to
1526 Params are login_session, user_id
1527 Optional third parameter is the transactions type. defaults to all
1530 __PACKAGE__->register_method(
1531 method => "user_transactions",
1532 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1533 notes => <<" NOTES");
1534 Returns an object/hash of transaction, circ, title where transaction = an open
1535 user transaction that has a balance (mbts objects), circ is the attached
1536 circluation, and title is the title the circ points to
1537 Params are login_session, user_id
1538 Optional third parameter is the transaction type. defaults to all
1541 __PACKAGE__->register_method(
1542 method => "user_transactions",
1543 api_name => "open-ils.actor.user.transactions.count",
1544 notes => <<" NOTES");
1545 Returns an object/hash of transaction, circ, title where transaction = an open
1546 user transactions (mbts objects), circ is the attached circluation, and title
1547 is the title the circ points to
1548 Params are login_session, user_id
1549 Optional third parameter is the transactions type. defaults to all
1552 __PACKAGE__->register_method(
1553 method => "user_transactions",
1554 api_name => "open-ils.actor.user.transactions.have_charge.count",
1555 notes => <<" NOTES");
1556 Returns an object/hash of transaction, circ, title where transaction = an open
1557 user transactions that has an initial charge (mbts objects), circ is the
1558 attached circluation, and title is the title the circ points to
1559 Params are login_session, user_id
1560 Optional third parameter is the transactions type. defaults to all
1563 __PACKAGE__->register_method(
1564 method => "user_transactions",
1565 api_name => "open-ils.actor.user.transactions.have_balance.count",
1566 notes => <<" NOTES");
1567 Returns an object/hash of transaction, circ, title where transaction = an open
1568 user transaction that has a balance (mbts objects), circ is the attached
1569 circluation, and title is the title the circ points to
1570 Params are login_session, user_id
1571 Optional third parameter is the transaction type. defaults to all
1574 __PACKAGE__->register_method(
1575 method => "user_transactions",
1576 api_name => "open-ils.actor.user.transactions.have_balance.total",
1577 notes => <<" NOTES");
1578 Returns an object/hash of transaction, circ, title where transaction = an open
1579 user transaction that has a balance (mbts objects), circ is the attached
1580 circluation, and title is the title the circ points to
1581 Params are login_session, user_id
1582 Optional third parameter is the transaction type. defaults to all
1587 sub user_transactions {
1588 my( $self, $client, $login_session, $user_id, $type ) = @_;
1590 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1591 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1592 return $evt if $evt;
1594 my $api = $self->api_name();
1598 if(defined($type)) { @xact = (xact_type => $type);
1600 } else { @xact = (); }
1603 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1604 ->run($login_session => $user_id => $type);
1606 if($api =~ /have_charge/o) {
1608 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1610 } elsif($api =~ /have_balance/o) {
1612 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1615 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1619 if($api =~ /total/o) {
1621 for my $t (@$trans) {
1622 $total += $t->balance_owed;
1625 $logger->debug("Total balance owed by user $user_id: $total");
1629 if($api =~ /count/o) { return scalar @$trans; }
1630 if($api !~ /fleshed/o) { return $trans; }
1633 for my $t (@$trans) {
1635 if( $t->xact_type ne 'circulation' ) {
1636 push @resp, {transaction => $t};
1640 my $circ = $apputils->simple_scalar_request(
1642 "open-ils.cstore.direct.action.circulation.retrieve",
1647 my $title = $apputils->simple_scalar_request(
1649 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1650 $circ->target_copy );
1654 my $u = OpenILS::Utils::ModsParser->new();
1655 $u->start_mods_batch($title->marc());
1656 my $mods = $u->finish_mods_batch();
1657 $mods->doc_id($title->id) if $mods;
1659 push @resp, {transaction => $t, circ => $circ, record => $mods };
1667 __PACKAGE__->register_method(
1668 method => "user_transaction_retrieve",
1669 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1671 notes => <<" NOTES");
1672 Returns a fleshedtransaction record
1674 __PACKAGE__->register_method(
1675 method => "user_transaction_retrieve",
1676 api_name => "open-ils.actor.user.transaction.retrieve",
1678 notes => <<" NOTES");
1679 Returns a transaction record
1681 sub user_transaction_retrieve {
1682 my( $self, $client, $login_session, $bill_id ) = @_;
1684 # XXX I think I'm deprecated... make sure
1686 my $trans = $apputils->simple_scalar_request(
1688 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1692 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1693 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1694 return $evt if $evt;
1696 my $api = $self->api_name();
1697 if($api !~ /fleshed/o) { return $trans; }
1699 if( $trans->xact_type ne 'circulation' ) {
1700 $logger->debug("Returning non-circ transaction");
1701 return {transaction => $trans};
1704 my $circ = $apputils->simple_scalar_request(
1706 "open-ils..direct.action.circulation.retrieve",
1709 return {transaction => $trans} unless $circ;
1710 $logger->debug("Found the circ transaction");
1712 my $title = $apputils->simple_scalar_request(
1714 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1715 $circ->target_copy );
1717 return {transaction => $trans, circ => $circ } unless $title;
1718 $logger->debug("Found the circ title");
1722 my $u = OpenILS::Utils::ModsParser->new();
1723 $u->start_mods_batch($title->marc());
1724 $mods = $u->finish_mods_batch();
1726 if ($title->id == OILS_PRECAT_RECORD) {
1727 my $copy = $apputils->simple_scalar_request(
1729 "open-ils.cstore.direct.asset.copy.retrieve",
1730 $circ->target_copy );
1732 $mods = new Fieldmapper::metabib::virtual_record;
1733 $mods->doc_id(OILS_PRECAT_RECORD);
1734 $mods->title($copy->dummy_title);
1735 $mods->author($copy->dummy_author);
1739 $logger->debug("MODSized the circ title");
1741 return {transaction => $trans, circ => $circ, record => $mods };
1745 __PACKAGE__->register_method(
1746 method => "hold_request_count",
1747 api_name => "open-ils.actor.user.hold_requests.count",
1749 notes => <<" NOTES");
1750 Returns hold ready/total counts
1752 sub hold_request_count {
1753 my( $self, $client, $login_session, $userid ) = @_;
1755 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1756 $login_session, $userid, 'VIEW_HOLD' );
1757 return $evt if $evt;
1760 my $holds = $apputils->simple_scalar_request(
1762 "open-ils.cstore.direct.action.hold_request.search.atomic",
1765 fulfillment_time => {"=" => undef },
1766 cancel_time => undef,
1771 for my $h (@$holds) {
1772 next unless $h->capture_time and $h->current_copy;
1774 my $copy = $apputils->simple_scalar_request(
1776 "open-ils.cstore.direct.asset.copy.retrieve",
1780 if ($copy and $copy->status == 8) {
1785 return { total => scalar(@$holds), ready => scalar(@ready) };
1789 __PACKAGE__->register_method(
1790 method => "checkedout_count",
1791 api_name => "open-ils.actor.user.checked_out.count__",
1793 notes => <<" NOTES");
1794 Returns a transaction record
1798 sub checkedout_count {
1799 my( $self, $client, $login_session, $userid ) = @_;
1801 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1802 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1803 return $evt if $evt;
1805 my $circs = $apputils->simple_scalar_request(
1807 "open-ils.cstore.direct.action.circulation.search.atomic",
1808 { usr => $userid, stop_fines => undef }
1809 #{ usr => $userid, checkin_time => {"=" => undef } }
1812 my $parser = DateTime::Format::ISO8601->new;
1815 for my $c (@$circs) {
1816 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1817 my $due = $due_dt->epoch;
1819 if ($due < DateTime->today->epoch) {
1824 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1828 __PACKAGE__->register_method(
1829 method => "checked_out",
1830 api_name => "open-ils.actor.user.checked_out",
1833 Returns a structure of circulations objects sorted by
1834 out, overdue, lost, claims_returned, long_overdue.
1835 A list of IDs are returned of each type.
1836 lost, long_overdue, and claims_returned circ will not
1837 be "finished" (there is an outstanding balance or some
1838 other pending action on the circ).
1840 The .count method also includes a 'total' field which
1841 sums all "open" circs
1845 __PACKAGE__->register_method(
1846 method => "checked_out",
1847 api_name => "open-ils.actor.user.checked_out.count",
1849 signature => q/@see open-ils.actor.user.checked_out/
1853 my( $self, $conn, $auth, $userid ) = @_;
1855 my $e = new_editor(authtoken=>$auth);
1856 return $e->event unless $e->checkauth;
1858 if( $userid ne $e->requestor->id ) {
1859 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1862 my $count = $self->api_name =~ /count/;
1863 return _checked_out( $count, $e, $userid );
1867 my( $iscount, $e, $userid ) = @_;
1870 my $meth = 'open-ils.storage.actor.user.checked_out';
1871 $meth = "$meth.count" if $iscount;
1872 return $U->storagereq($meth, $userid);
1874 # XXX Old code - moved to storage
1875 #------------------------------------------------------------------------------
1876 #------------------------------------------------------------------------------
1877 my $circs = $e->search_action_circulation(
1878 { usr => $userid, checkin_time => undef });
1880 my $parser = DateTime::Format::ISO8601->new;
1882 # split the circs up into overdue and not-overdue circs
1884 for my $c (@$circs) {
1885 if( $c->due_date ) {
1886 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1887 my $due = $due_dt->epoch;
1888 if ($due < DateTime->today->epoch) {
1898 my( @open, @od, @lost, @cr, @lo );
1900 while (my $c = shift(@out)) {
1901 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1902 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1903 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1904 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1907 while (my $c = shift(@overdue)) {
1908 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1909 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1910 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1911 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1916 total => @open + @od + @lost + @cr + @lo,
1917 out => scalar(@open),
1918 overdue => scalar(@od),
1919 lost => scalar(@lost),
1920 claims_returned => scalar(@cr),
1921 long_overdue => scalar(@lo)
1929 claims_returned => \@cr,
1930 long_overdue => \@lo
1935 sub _checked_out_WHAT {
1936 my( $iscount, $e, $userid ) = @_;
1938 my $circs = $e->search_action_circulation(
1939 { usr => $userid, stop_fines => undef });
1941 my $mcircs = $e->search_action_circulation(
1944 checkin_time => undef,
1945 xact_finish => undef,
1949 push( @$circs, @$mcircs );
1951 my $parser = DateTime::Format::ISO8601->new;
1953 # split the circs up into overdue and not-overdue circs
1955 for my $c (@$circs) {
1956 if( $c->due_date ) {
1957 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1958 my $due = $due_dt->epoch;
1959 if ($due < DateTime->today->epoch) {
1960 push @overdue, $c->id;
1969 # grab all of the lost, claims-returned, and longoverdue circs
1970 #my $open = $e->search_action_circulation(
1971 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1974 # these items have stop_fines, but no xact_finish, so money
1975 # is owed on them and they have not been checked in
1976 my $open = $e->search_action_circulation(
1979 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1980 xact_finish => undef,
1981 checkin_time => undef,
1986 my( @lost, @cr, @lo );
1987 for my $c (@$open) {
1988 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1989 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1990 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1996 total => @$circs + @lost + @cr + @lo,
1997 out => scalar(@out),
1998 overdue => scalar(@overdue),
1999 lost => scalar(@lost),
2000 claims_returned => scalar(@cr),
2001 long_overdue => scalar(@lo)
2007 overdue => \@overdue,
2009 claims_returned => \@cr,
2010 long_overdue => \@lo
2016 __PACKAGE__->register_method(
2017 method => "checked_in_with_fines",
2018 api_name => "open-ils.actor.user.checked_in_with_fines",
2020 signature => q/@see open-ils.actor.user.checked_out/
2022 sub checked_in_with_fines {
2023 my( $self, $conn, $auth, $userid ) = @_;
2025 my $e = new_editor(authtoken=>$auth);
2026 return $e->event unless $e->checkauth;
2028 if( $userid ne $e->requestor->id ) {
2029 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2032 # money is owed on these items and they are checked in
2033 my $open = $e->search_action_circulation(
2036 xact_finish => undef,
2037 checkin_time => { "!=" => undef },
2042 my( @lost, @cr, @lo );
2043 for my $c (@$open) {
2044 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2045 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2046 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2051 claims_returned => \@cr,
2052 long_overdue => \@lo
2064 __PACKAGE__->register_method(
2065 method => "user_transaction_history",
2066 api_name => "open-ils.actor.user.transactions.history",
2068 notes => <<" NOTES");
2069 Returns a list of billable transaction ids for a user, optionally by type
2071 __PACKAGE__->register_method(
2072 method => "user_transaction_history",
2073 api_name => "open-ils.actor.user.transactions.history.have_charge",
2075 notes => <<" NOTES");
2076 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2078 __PACKAGE__->register_method(
2079 method => "user_transaction_history",
2080 api_name => "open-ils.actor.user.transactions.history.have_balance",
2082 notes => <<" NOTES");
2083 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2085 __PACKAGE__->register_method(
2086 method => "user_transaction_history",
2087 api_name => "open-ils.actor.user.transactions.history.still_open",
2089 notes => <<" NOTES");
2090 Returns a list of billable transaction ids for a user that are not finished
2092 __PACKAGE__->register_method(
2093 method => "user_transaction_history",
2094 api_name => "open-ils.actor.user.transactions.history.have_bill",
2096 notes => <<" NOTES");
2097 Returns a list of billable transaction ids for a user that has billings
2103 sub _user_transaction_history {
2104 my( $self, $client, $login_session, $user_id, $type ) = @_;
2106 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2107 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2108 return $evt if $evt;
2110 my $api = $self->api_name();
2115 @xact = (xact_type => $type) if(defined($type));
2116 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2117 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2119 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2121 my $trans = $apputils->simple_scalar_request(
2123 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2124 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2126 return [ map { $_->id } @$trans ];
2130 =head SEE APPUTILS.PM
2135 for my $x (@xacts) {
2136 my $s = new Fieldmapper::money::billable_transaction_summary;
2139 $s->xact_start( $x->xact_start );
2140 $s->xact_finish( $x->xact_finish );
2144 for my $b (@{ $x->billings }) {
2145 next if ($U->is_true($b->voided));
2146 $to += ($b->amount * 100);
2147 $lb ||= $b->billing_ts;
2148 if ($b->billing_ts ge $lb) {
2149 $lb = $b->billing_ts;
2150 $s->last_billing_note($b->note);
2151 $s->last_billing_ts($b->billing_ts);
2152 $s->last_billing_type($b->billing_type);
2156 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2160 for my $p (@{ $x->payments }) {
2161 next if ($U->is_true($p->voided));
2162 $tp += ($p->amount * 100);
2163 $lp ||= $p->payment_ts;
2164 if ($p->payment_ts ge $lp) {
2165 $lp = $p->payment_ts;
2166 $s->last_payment_note($p->note);
2167 $s->last_payment_ts($p->payment_ts);
2168 $s->last_payment_type($p->payment_type);
2171 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2173 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2175 $s->xact_type( 'grocery' ) if ($x->grocery);
2176 $s->xact_type( 'circulation' ) if ($x->circulation);
2185 sub user_transaction_history {
2186 my( $self, $conn, $auth, $userid, $type ) = @_;
2188 # run inside of a transaction to prevent replication delays
2189 my $e = new_editor(xact=>1, authtoken=>$auth);
2190 return $e->die_event unless $e->checkauth;
2192 if( $e->requestor->id ne $userid ) {
2193 return $e->die_event
2194 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2197 my $api = $self->api_name;
2198 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2200 my @xacts = @{ $e->search_money_billable_transaction(
2201 [ { usr => $userid, @xact_finish },
2203 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2204 order_by => { mbt => 'xact_start DESC' },
2212 #my @mbts = _make_mbts( @xacts );
2213 my @mbts = $U->make_mbts( @xacts );
2215 if(defined($type)) {
2216 @mbts = grep { $_->xact_type eq $type } @mbts;
2219 if($api =~ /have_balance/o) {
2220 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2223 if($api =~ /have_charge/o) {
2224 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2227 if($api =~ /have_bill/o) {
2228 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2236 __PACKAGE__->register_method(
2237 method => "user_perms",
2238 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2240 notes => <<" NOTES");
2241 Returns a list of permissions
2244 my( $self, $client, $authtoken, $user ) = @_;
2246 my( $staff, $evt ) = $apputils->checkses($authtoken);
2247 return $evt if $evt;
2249 $user ||= $staff->id;
2251 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2255 return $apputils->simple_scalar_request(
2257 "open-ils.storage.permission.user_perms.atomic",
2261 __PACKAGE__->register_method(
2262 method => "retrieve_perms",
2263 api_name => "open-ils.actor.permissions.retrieve",
2264 notes => <<" NOTES");
2265 Returns a list of permissions
2267 sub retrieve_perms {
2268 my( $self, $client ) = @_;
2269 return $apputils->simple_scalar_request(
2271 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2272 { id => { '!=' => undef } }
2276 __PACKAGE__->register_method(
2277 method => "retrieve_groups",
2278 api_name => "open-ils.actor.groups.retrieve",
2279 notes => <<" NOTES");
2280 Returns a list of user groupss
2282 sub retrieve_groups {
2283 my( $self, $client ) = @_;
2284 return new_editor()->retrieve_all_permission_grp_tree();
2287 __PACKAGE__->register_method(
2288 method => "retrieve_org_address",
2289 api_name => "open-ils.actor.org_unit.address.retrieve",
2290 notes => <<' NOTES');
2291 Returns an org_unit address by ID
2292 @param An org_address ID
2294 sub retrieve_org_address {
2295 my( $self, $client, $id ) = @_;
2296 return $apputils->simple_scalar_request(
2298 "open-ils.cstore.direct.actor.org_address.retrieve",
2303 __PACKAGE__->register_method(
2304 method => "retrieve_groups_tree",
2305 api_name => "open-ils.actor.groups.tree.retrieve",
2306 notes => <<" NOTES");
2307 Returns a list of user groups
2309 sub retrieve_groups_tree {
2310 my( $self, $client ) = @_;
2311 return new_editor()->search_permission_grp_tree(
2316 flesh_fields => { pgt => ["children"] },
2317 order_by => { pgt => 'name'}
2324 # turns an org list into an org tree
2326 sub build_group_tree {
2328 my( $self, $grplist) = @_;
2330 return $grplist unless (
2331 ref($grplist) and @$grplist > 1 );
2333 my @list = sort { $a->name cmp $b->name } @$grplist;
2336 for my $grp (@list) {
2338 if ($grp and !defined($grp->parent)) {
2342 my ($parent) = grep { $_->id == $grp->parent} @list;
2344 $parent->children([]) unless defined($parent->children);
2345 push( @{$parent->children}, $grp );
2353 __PACKAGE__->register_method(
2354 method => "add_user_to_groups",
2355 api_name => "open-ils.actor.user.set_groups",
2356 notes => <<" NOTES");
2357 Adds a user to one or more permission groups
2360 sub add_user_to_groups {
2361 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2363 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2364 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2365 return $evt if $evt;
2367 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2368 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2369 return $evt if $evt;
2371 $apputils->simplereq(
2373 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2375 for my $group (@$groups) {
2376 my $link = Fieldmapper::permission::usr_grp_map->new;
2378 $link->usr($userid);
2380 my $id = $apputils->simplereq(
2382 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2388 __PACKAGE__->register_method(
2389 method => "get_user_perm_groups",
2390 api_name => "open-ils.actor.user.get_groups",
2391 notes => <<" NOTES");
2392 Retrieve a user's permission groups.
2396 sub get_user_perm_groups {
2397 my( $self, $client, $authtoken, $userid ) = @_;
2399 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2400 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2401 return $evt if $evt;
2403 return $apputils->simplereq(
2405 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2408 __PACKAGE__->register_method(
2409 method => "get_user_work_ous",
2410 api_name => "open-ils.actor.user.get_work_ous",
2411 notes => <<" NOTES");
2412 Retrieve a user's work org units.
2416 sub get_user_work_ous {
2417 my( $self, $client, $authtoken, $userid ) = @_;
2419 my( $requestor, $evt ) = $apputils->checksesperm( $authtoken, 'ASSIGN_WORK_ORG_UNIT' );
2420 return $evt if $evt;
2422 return $apputils->simplereq(
2424 'open-ils.cstore.direct.permission.usr_work_ou_map.search.atomic', { usr => $userid } );
2429 __PACKAGE__->register_method (
2430 method => 'register_workstation',
2431 api_name => 'open-ils.actor.workstation.register.override',
2432 signature => q/@see open-ils.actor.workstation.register/);
2434 __PACKAGE__->register_method (
2435 method => 'register_workstation',
2436 api_name => 'open-ils.actor.workstation.register',
2438 Registers a new workstion in the system
2439 @param authtoken The login session key
2440 @param name The name of the workstation id
2441 @param owner The org unit that owns this workstation
2442 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2443 if the name is already in use.
2446 sub register_workstation {
2447 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2449 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2450 return $e->die_event unless $e->checkauth;
2451 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2452 my $existing = $e->search_actor_workstation({name => $name})->[0];
2456 if( $self->api_name =~ /override/o ) {
2457 # workstation with the given name exists.
2459 if($owner ne $existing->owning_lib) {
2460 # if necessary, update the owning_lib of the workstation
2462 $logger->info("changing owning lib of workstation ".$existing->id.
2463 " from ".$existing->owning_lib." to $owner");
2464 return $e->die_event unless
2465 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2467 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2469 $existing->owning_lib($owner);
2470 return $e->die_event unless $e->update_actor_workstation($existing);
2476 "attempt to register an existing workstation. returning existing ID");
2479 return $existing->id;
2482 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2486 my $ws = Fieldmapper::actor::workstation->new;
2487 $ws->owning_lib($owner);
2489 $e->create_actor_workstation($ws) or return $e->die_event;
2491 return $ws->id; # note: editor sets the id on the new object for us
2494 __PACKAGE__->register_method (
2495 method => 'workstation_list',
2496 api_name => 'open-ils.actor.workstation.list',
2498 Returns a list of workstations registered at the given location
2499 @param authtoken The login session key
2500 @param ids A list of org_unit.id's for the workstation owners
2503 sub workstation_list {
2504 my( $self, $conn, $authtoken, @orgs ) = @_;
2506 my $e = new_editor(authtoken=>$authtoken);
2507 return $e->event unless $e->checkauth;
2512 unless $e->allowed('REGISTER_WORKSTATION', $o);
2513 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2524 __PACKAGE__->register_method (
2525 method => 'fetch_patron_note',
2526 api_name => 'open-ils.actor.note.retrieve.all',
2528 Returns a list of notes for a given user
2529 Requestor must have VIEW_USER permission if pub==false and
2530 @param authtoken The login session key
2531 @param args Hash of params including
2532 patronid : the patron's id
2533 pub : true if retrieving only public notes
2537 sub fetch_patron_note {
2538 my( $self, $conn, $authtoken, $args ) = @_;
2539 my $patronid = $$args{patronid};
2541 my($reqr, $evt) = $U->checkses($authtoken);
2542 return $evt if $evt;
2545 ($patron, $evt) = $U->fetch_user($patronid);
2546 return $evt if $evt;
2549 if( $patronid ne $reqr->id ) {
2550 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2551 return $evt if $evt;
2553 return $U->cstorereq(
2554 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2555 { usr => $patronid, pub => 't' } );
2558 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2559 return $evt if $evt;
2561 return $U->cstorereq(
2562 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2565 __PACKAGE__->register_method (
2566 method => 'create_user_note',
2567 api_name => 'open-ils.actor.note.create',
2569 Creates a new note for the given user
2570 @param authtoken The login session key
2571 @param note The note object
2574 sub create_user_note {
2575 my( $self, $conn, $authtoken, $note ) = @_;
2576 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2577 return $e->die_event unless $e->checkauth;
2579 my $user = $e->retrieve_actor_user($note->usr)
2580 or return $e->die_event;
2582 return $e->die_event unless
2583 $e->allowed('UPDATE_USER',$user->home_ou);
2585 $note->creator($e->requestor->id);
2586 $e->create_actor_usr_note($note) or return $e->die_event;
2592 __PACKAGE__->register_method (
2593 method => 'delete_user_note',
2594 api_name => 'open-ils.actor.note.delete',
2596 Deletes a note for the given user
2597 @param authtoken The login session key
2598 @param noteid The note id
2601 sub delete_user_note {
2602 my( $self, $conn, $authtoken, $noteid ) = @_;
2604 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2605 return $e->die_event unless $e->checkauth;
2606 my $note = $e->retrieve_actor_usr_note($noteid)
2607 or return $e->die_event;
2608 my $user = $e->retrieve_actor_user($note->usr)
2609 or return $e->die_event;
2610 return $e->die_event unless
2611 $e->allowed('UPDATE_USER', $user->home_ou);
2613 $e->delete_actor_usr_note($note) or return $e->die_event;
2619 __PACKAGE__->register_method (
2620 method => 'update_user_note',
2621 api_name => 'open-ils.actor.note.update',
2623 @param authtoken The login session key
2624 @param note The note
2628 sub update_user_note {
2629 my( $self, $conn, $auth, $note ) = @_;
2630 my $e = new_editor(authtoken=>$auth, xact=>1);
2631 return $e->event unless $e->checkauth;
2632 my $patron = $e->retrieve_actor_user($note->usr)
2633 or return $e->event;
2634 return $e->event unless
2635 $e->allowed('UPDATE_USER', $patron->home_ou);
2636 $e->update_actor_user_note($note)
2637 or return $e->event;
2645 __PACKAGE__->register_method (
2646 method => 'create_closed_date',
2647 api_name => 'open-ils.actor.org_unit.closed_date.create',
2649 Creates a new closing entry for the given org_unit
2650 @param authtoken The login session key
2651 @param note The closed_date object
2654 sub create_closed_date {
2655 my( $self, $conn, $authtoken, $cd ) = @_;
2657 my( $user, $evt ) = $U->checkses($authtoken);
2658 return $evt if $evt;
2660 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2661 return $evt if $evt;
2663 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2665 my $id = $U->storagereq(
2666 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2667 return $U->DB_UPDATE_FAILED($cd) unless $id;
2672 __PACKAGE__->register_method (
2673 method => 'delete_closed_date',
2674 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2676 Deletes a closing entry for the given org_unit
2677 @param authtoken The login session key
2678 @param noteid The close_date id
2681 sub delete_closed_date {
2682 my( $self, $conn, $authtoken, $cd ) = @_;
2684 my( $user, $evt ) = $U->checkses($authtoken);
2685 return $evt if $evt;
2688 ($cd_obj, $evt) = fetch_closed_date($cd);
2689 return $evt if $evt;
2691 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2692 return $evt if $evt;
2694 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2696 my $stat = $U->storagereq(
2697 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2698 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2703 __PACKAGE__->register_method(
2704 method => 'usrname_exists',
2705 api_name => 'open-ils.actor.username.exists',
2707 Returns 1 if the requested username exists, returns 0 otherwise
2711 sub usrname_exists {
2712 my( $self, $conn, $auth, $usrname ) = @_;
2713 my $e = new_editor(authtoken=>$auth);
2714 return $e->event unless $e->checkauth;
2715 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2716 return $$a[0] if $a and @$a;
2720 __PACKAGE__->register_method(
2721 method => 'barcode_exists',
2722 api_name => 'open-ils.actor.barcode.exists',
2724 Returns 1 if the requested barcode exists, returns 0 otherwise
2728 sub barcode_exists {
2729 my( $self, $conn, $auth, $barcode ) = @_;
2730 my $e = new_editor(authtoken=>$auth);
2731 return $e->event unless $e->checkauth;
2732 my $card = $e->search_actor_card({barcode => $barcode});
2733 return 0 unless @$card;
2734 return $card->[0]->usr;
2738 __PACKAGE__->register_method(
2739 method => 'retrieve_net_levels',
2740 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2743 sub retrieve_net_levels {
2744 my( $self, $conn, $auth ) = @_;
2745 my $e = new_editor(authtoken=>$auth);
2746 return $e->event unless $e->checkauth;
2747 return $e->retrieve_all_config_net_access_level();
2751 __PACKAGE__->register_method(
2752 method => 'fetch_org_by_shortname',
2753 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2755 sub fetch_org_by_shortname {
2756 my( $self, $conn, $sname ) = @_;
2757 my $e = new_editor();
2758 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2759 return $e->event unless $org;
2764 __PACKAGE__->register_method(
2765 method => 'session_home_lib',
2766 api_name => 'open-ils.actor.session.home_lib',
2769 sub session_home_lib {
2770 my( $self, $conn, $auth ) = @_;
2771 my $e = new_editor(authtoken=>$auth);
2772 return undef unless $e->checkauth;
2773 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2774 return $org->shortname;
2777 __PACKAGE__->register_method(
2778 method => 'session_safe_token',
2779 api_name => 'open-ils.actor.session.safe_token',
2781 Returns a hashed session ID that is safe for export to the world.
2782 This safe token will expire after 1 hour of non-use.
2783 @param auth Active authentication token
2787 sub session_safe_token {
2788 my( $self, $conn, $auth ) = @_;
2789 my $e = new_editor(authtoken=>$auth);
2790 return undef unless $e->checkauth;
2792 my $safe_token = md5_hex($auth);
2794 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2796 # Add more like the following if needed...
2798 "safe-token-home_lib-shortname-$safe_token",
2799 $e->retrieve_actor_org_unit(
2800 $e->requestor->home_ou
2809 __PACKAGE__->register_method(
2810 method => 'safe_token_home_lib',
2811 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2813 Returns the home library shortname from the session
2814 asscociated with a safe token from generated by
2815 open-ils.actor.session.safe_token.
2816 @param safe_token Active safe token
2820 sub safe_token_home_lib {
2821 my( $self, $conn, $safe_token ) = @_;
2823 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2824 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2829 __PACKAGE__->register_method(
2830 method => 'slim_tree',
2831 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2834 my $tree = new_editor()->search_actor_org_unit(
2836 {"parent_ou" => undef },
2839 flesh_fields => { aou => ['children'] },
2840 order_by => { aou => 'name'},
2841 select => { aou => ["id","shortname", "name"]},
2846 return trim_tree($tree);
2852 return undef unless $tree;
2854 code => $tree->shortname,
2855 name => $tree->name,
2857 if( $tree->children and @{$tree->children} ) {
2858 $htree->{children} = [];
2859 for my $c (@{$tree->children}) {
2860 push( @{$htree->{children}}, trim_tree($c) );
2868 __PACKAGE__->register_method(
2869 method => "update_penalties",
2870 api_name => "open-ils.actor.user.penalties.update");
2871 sub update_penalties {
2872 my( $self, $conn, $auth, $userid ) = @_;
2873 my $e = new_editor(authtoken=>$auth);
2874 return $e->event unless $e->checkauth;
2875 $U->update_patron_penalties(
2877 patronid => $userid,
2884 __PACKAGE__->register_method(
2885 method => "user_retrieve_fleshed_by_id",
2886 api_name => "open-ils.actor.user.fleshed.retrieve",);
2888 sub user_retrieve_fleshed_by_id {
2889 my( $self, $client, $auth, $user_id, $fields ) = @_;
2890 my $e = new_editor(authtoken => $auth);
2891 return $e->event unless $e->checkauth;
2893 if( $e->requestor->id != $user_id ) {
2894 return $e->event unless $e->allowed('VIEW_USER');
2900 "standing_penalties",
2904 "stat_cat_entries" ];
2905 return new_flesh_user($user_id, $fields, $e);
2909 sub new_flesh_user {
2912 my $fields = shift || [];
2913 my $e = shift || new_editor(xact=>1);
2915 my $user = $e->retrieve_actor_user(
2920 "flesh_fields" => { "au" => $fields }
2923 ) or return $e->event;
2926 if( grep { $_ eq 'addresses' } @$fields ) {
2928 $user->addresses([]) unless @{$user->addresses};
2930 if( ref $user->billing_address ) {
2931 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2932 push( @{$user->addresses}, $user->billing_address );
2936 if( ref $user->mailing_address ) {
2937 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2938 push( @{$user->addresses}, $user->mailing_address );
2944 $user->clear_passwd();
2951 __PACKAGE__->register_method(
2952 method => "user_retrieve_parts",
2953 api_name => "open-ils.actor.user.retrieve.parts",);
2955 sub user_retrieve_parts {
2956 my( $self, $client, $auth, $user_id, $fields ) = @_;
2957 my $e = new_editor(authtoken => $auth);
2958 return $e->event unless $e->checkauth;
2959 if( $e->requestor->id != $user_id ) {
2960 return $e->event unless $e->allowed('VIEW_USER');
2963 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2964 push(@resp, $user->$_()) for(@$fields);
2970 __PACKAGE__->register_method(
2971 method => 'user_opt_in_enabled',
2972 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2974 @return 1 if user opt-in is globally enabled, 0 otherwise.
2977 sub user_opt_in_enabled {
2978 my($self, $conn) = @_;
2979 my $sc = OpenSRF::Utils::SettingsClient->new;
2980 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2985 __PACKAGE__->register_method(
2986 method => 'user_opt_in_at_org',
2987 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2989 @param $auth The auth token
2990 @param user_id The ID of the user to test
2991 @return 1 if the user has opted in at the specified org,
2992 event on error, and 0 otherwise. /);
2993 sub user_opt_in_at_org {
2994 my($self, $conn, $auth, $user_id) = @_;
2996 # see if we even need to enforce the opt-in value
2997 return 1 unless $self->user_opt_in_enabled;
2999 my $e = new_editor(authtoken => $auth);
3000 return $e->event unless $e->checkauth;
3001 my $org_id = $e->requestor->ws_ou;
3003 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3004 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3006 # user is automatically opted-in at the home org
3007 return 1 if $user->home_ou eq $org_id;
3009 my $vals = $e->search_actor_usr_org_unit_opt_in(
3010 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3016 __PACKAGE__->register_method(
3017 method => 'create_user_opt_in_at_org',
3018 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3020 @param $auth The auth token
3021 @param user_id The ID of the user to test
3022 @return The ID of the newly created object, event on error./);
3024 sub create_user_opt_in_at_org {
3025 my($self, $conn, $auth, $user_id) = @_;
3027 my $e = new_editor(authtoken => $auth, xact=>1);
3028 return $e->die_event unless $e->checkauth;
3029 my $org_id = $e->requestor->ws_ou;
3031 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3032 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3034 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3036 $opt_in->org_unit($org_id);
3037 $opt_in->usr($user_id);
3038 $opt_in->staff($e->requestor->id);
3039 $opt_in->opt_in_ts('now');
3040 $opt_in->opt_in_ws($e->requestor->wsid);
3042 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3043 or return $e->die_event;