1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
5 $Data::Dumper::Indent = 0;
8 use Digest::MD5 qw(md5_hex);
10 use OpenSRF::EX qw(:try);
13 use OpenILS::Application::AppUtils;
15 use OpenILS::Utils::Fieldmapper;
16 use OpenILS::Utils::ModsParser;
17 use OpenSRF::Utils::Logger qw/$logger/;
18 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::Cache;
22 use OpenSRF::Utils::JSON;
24 use DateTime::Format::ISO8601;
25 use OpenILS::Const qw/:const/;
27 use OpenILS::Application::Actor::Container;
28 use OpenILS::Application::Actor::ClosedDates;
30 use OpenILS::Utils::CStoreEditor qw/:funcs/;
32 use OpenILS::Application::Actor::UserGroups;
34 OpenILS::Application::Actor::Container->initialize();
35 OpenILS::Application::Actor::UserGroups->initialize();
36 OpenILS::Application::Actor::ClosedDates->initialize();
39 my $apputils = "OpenILS::Application::AppUtils";
42 sub _d { warn "Patron:\n" . Dumper(shift()); }
47 my $set_user_settings;
50 __PACKAGE__->register_method(
51 method => "set_user_settings",
52 api_name => "open-ils.actor.patron.settings.update",
54 sub set_user_settings {
55 my( $self, $client, $user_session, $uid, $settings ) = @_;
57 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
59 my( $staff, $user, $evt ) =
60 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
64 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
66 $_->[1]->{value} = OpenSRF::Utils::JSON->perl2JSON($_->[1]->{value}) for @params;
68 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
70 my $ses = $U->start_db_session();
71 my $stat = $ses->request(
72 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
73 $U->commit_db_session($ses);
80 __PACKAGE__->register_method(
81 method => "set_ou_settings",
82 api_name => "open-ils.actor.org_unit.settings.update",
85 my( $self, $client, $user_session, $ouid, $settings ) = @_;
87 my( $staff, $evt ) = $apputils->checkses( $user_session );
89 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
93 for my $set (keys %$settings) {
95 my $json = OpenSRF::Utils::JSON->perl2JSON($$settings{$set});
96 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
99 { org_unit => $ouid, name => $set },
100 { value => $json } );
103 my $ses = $U->start_db_session();
104 my $stat = $ses->request(
105 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
106 $U->commit_db_session($ses);
112 my $fetch_user_settings;
113 my $fetch_ou_settings;
115 __PACKAGE__->register_method(
116 method => "user_settings",
117 api_name => "open-ils.actor.patron.settings.retrieve",
120 my( $self, $client, $user_session, $uid, $setting ) = @_;
122 my( $staff, $user, $evt ) =
123 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
126 $logger->debug("User " . $staff->id . " fetching user $uid\n");
127 my $s = $apputils->simplereq(
129 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
131 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
133 return $$settings{$setting} if $setting;
139 __PACKAGE__->register_method(
140 method => "ou_settings",
141 api_name => "open-ils.actor.org_unit.settings.retrieve",
144 my( $self, $client, $ouid ) = @_;
146 $logger->info("Fetching org unit settings for org $ouid");
148 my $s = $apputils->simplereq(
150 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
152 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
157 __PACKAGE__->register_method(
158 api_name => 'open-ils.actor.ou_setting.ancestor_default',
159 method => 'ou_ancestor_setting',
162 # ------------------------------------------------------------------
163 # Attempts to find the org setting value for a given org. if not
164 # found at the requested org, searches up the org tree until it
165 # finds a parent that has the requested setting.
166 # when found, returns { org => $id, value => $value }
167 # otherwise, returns NULL
168 # ------------------------------------------------------------------
169 sub ou_ancestor_setting {
170 my( $self, $client, $orgid, $name ) = @_;
171 return $U->ou_ancestor_setting($orgid, $name);
177 __PACKAGE__->register_method (
178 method => "ou_setting_delete",
179 api_name => 'open-ils.actor.org_setting.delete',
181 Deletes a specific org unit setting for a specific location
182 @param authtoken The login session key
183 @param orgid The org unit whose setting we're changing
184 @param setting The name of the setting to delete
185 @return True value on success.
189 sub ou_setting_delete {
190 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
191 my( $reqr, $evt) = $U->checkses($authtoken);
193 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
196 my $id = $U->cstorereq(
197 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
198 { name => $setting, org_unit => $orgid } );
200 $logger->debug("Retrieved setting $id in org unit setting delete");
202 my $s = $U->cstorereq(
203 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
205 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
219 __PACKAGE__->register_method(
220 method => "update_patron",
221 api_name => "open-ils.actor.patron.update",);
224 my( $self, $client, $user_session, $patron ) = @_;
226 my $session = $apputils->start_db_session();
230 $logger->info("Creating new patron...") if $patron->isnew;
231 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
233 my( $user_obj, $evt ) = $U->checkses($user_session);
236 $evt = check_group_perm($session, $user_obj, $patron);
240 # $new_patron is the patron in progress. $patron is the original patron
241 # passed in with the method. new_patron will change as the components
242 # of patron are added/updated.
246 # unflesh the real items on the patron
247 $patron->card( $patron->card->id ) if(ref($patron->card));
248 $patron->billing_address( $patron->billing_address->id )
249 if(ref($patron->billing_address));
250 $patron->mailing_address( $patron->mailing_address->id )
251 if(ref($patron->mailing_address));
253 # create/update the patron first so we can use his id
254 if($patron->isnew()) {
255 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
257 } else { $new_patron = $patron; }
259 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
262 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
265 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
268 # re-update the patron if anything has happened to him during this process
269 if($new_patron->ischanged()) {
270 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
274 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
277 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
280 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
283 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
286 if(!$patron->isnew) {
287 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
290 $apputils->commit_db_session($session);
291 my $fuser = flesh_user($new_patron->id());
294 # Log the new and old patron for investigation
295 $logger->info("$user_session updating patron object. orig patron object = ".
296 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
306 return new_flesh_user($id, [
309 "standing_penalties",
313 "stat_cat_entries" ] );
321 # clone and clear stuff that would break the database
325 my $new_patron = $patron->clone;
327 $new_patron->clear_billing_address();
328 $new_patron->clear_mailing_address();
329 $new_patron->clear_addresses();
330 $new_patron->clear_card();
331 $new_patron->clear_cards();
332 $new_patron->clear_id();
333 $new_patron->clear_isnew();
334 $new_patron->clear_ischanged();
335 $new_patron->clear_isdeleted();
336 $new_patron->clear_stat_cat_entries();
337 $new_patron->clear_permissions();
338 $new_patron->clear_standing_penalties();
348 my $user_obj = shift;
350 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
351 return (undef, $evt) if $evt;
353 my $ex = $session->request(
354 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
356 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
359 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
361 my $id = $session->request(
362 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
363 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
365 $logger->info("Successfully created new user [$id] in DB");
367 return ( $session->request(
368 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
372 sub check_group_perm {
373 my( $session, $requestor, $patron ) = @_;
376 # first let's see if the requestor has
377 # priveleges to update this user in any way
378 if( ! $patron->isnew ) {
379 my $p = $session->request(
380 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
382 # If we are the requestor (trying to update our own account)
383 # and we are not trying to change our profile, we're good
384 if( $p->id == $requestor->id and
385 $p->profile == $patron->profile ) {
390 $evt = group_perm_failed($session, $requestor, $p);
394 # They are allowed to edit this patron.. can they put the
395 # patron into the group requested?
396 $evt = group_perm_failed($session, $requestor, $patron);
402 sub group_perm_failed {
403 my( $session, $requestor, $patron ) = @_;
407 my $grpid = $patron->profile;
411 $logger->debug("user update looking for group perm for group $grpid");
412 $grp = $session->request(
413 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
414 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
416 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
418 $logger->info("user update checking perm $perm on user ".
419 $requestor->id." for update/create on user username=".$patron->usrname);
421 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
429 my( $session, $patron, $user_obj, $noperm) = @_;
431 $logger->info("Updating patron ".$patron->id." in DB");
436 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
437 return (undef, $evt) if $evt;
440 # update the password by itself to avoid the password protection magic
441 if( $patron->passwd ) {
442 my $s = $session->request(
443 'open-ils.storage.direct.actor.user.remote_update',
444 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
445 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
446 $patron->clear_passwd;
449 if(!$patron->ident_type) {
450 $patron->clear_ident_type;
451 $patron->clear_ident_value;
454 $evt = verify_last_xact($session, $patron);
455 return (undef, $evt) if $evt;
457 my $stat = $session->request(
458 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
459 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
464 sub verify_last_xact {
465 my( $session, $patron ) = @_;
466 return undef unless $patron->id and $patron->id > 0;
467 my $p = $session->request(
468 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
469 my $xact = $p->last_xact_id;
470 return undef unless $xact;
471 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
472 return OpenILS::Event->new('XACT_COLLISION')
473 if $xact != $patron->last_xact_id;
478 sub _check_dup_ident {
479 my( $session, $patron ) = @_;
481 return undef unless $patron->ident_value;
484 ident_type => $patron->ident_type,
485 ident_value => $patron->ident_value,
488 $logger->debug("patron update searching for dup ident values: " .
489 $patron->ident_type . ':' . $patron->ident_value);
491 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
493 my $dups = $session->request(
494 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
497 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
504 sub _add_update_addresses {
508 my $new_patron = shift;
512 my $current_id; # id of the address before creation
514 for my $address (@{$patron->addresses()}) {
516 next unless ref $address;
517 $current_id = $address->id();
519 if( $patron->billing_address() and
520 $patron->billing_address() == $current_id ) {
521 $logger->info("setting billing addr to $current_id");
522 $new_patron->billing_address($address->id());
523 $new_patron->ischanged(1);
526 if( $patron->mailing_address() and
527 $patron->mailing_address() == $current_id ) {
528 $new_patron->mailing_address($address->id());
529 $logger->info("setting mailing addr to $current_id");
530 $new_patron->ischanged(1);
534 if($address->isnew()) {
536 $address->usr($new_patron->id());
538 ($address, $evt) = _add_address($session,$address);
539 return (undef, $evt) if $evt;
541 # we need to get the new id
542 if( $patron->billing_address() and
543 $patron->billing_address() == $current_id ) {
544 $new_patron->billing_address($address->id());
545 $logger->info("setting billing addr to $current_id");
546 $new_patron->ischanged(1);
549 if( $patron->mailing_address() and
550 $patron->mailing_address() == $current_id ) {
551 $new_patron->mailing_address($address->id());
552 $logger->info("setting mailing addr to $current_id");
553 $new_patron->ischanged(1);
556 } elsif($address->ischanged() ) {
558 ($address, $evt) = _update_address($session, $address);
559 return (undef, $evt) if $evt;
561 } elsif($address->isdeleted() ) {
563 if( $address->id() == $new_patron->mailing_address() ) {
564 $new_patron->clear_mailing_address();
565 ($new_patron, $evt) = _update_patron($session, $new_patron);
566 return (undef, $evt) if $evt;
569 if( $address->id() == $new_patron->billing_address() ) {
570 $new_patron->clear_billing_address();
571 ($new_patron, $evt) = _update_patron($session, $new_patron);
572 return (undef, $evt) if $evt;
575 $evt = _delete_address($session, $address);
576 return (undef, $evt) if $evt;
580 return ( $new_patron, undef );
584 # adds an address to the db and returns the address with new id
586 my($session, $address) = @_;
587 $address->clear_id();
589 $logger->info("Creating new address at street ".$address->street1);
591 # put the address into the database
592 my $id = $session->request(
593 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
594 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
597 return ($address, undef);
601 sub _update_address {
602 my( $session, $address ) = @_;
604 $logger->info("Updating address ".$address->id." in the DB");
606 my $stat = $session->request(
607 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
609 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
610 return ($address, undef);
615 sub _add_update_cards {
619 my $new_patron = shift;
623 my $virtual_id; #id of the card before creation
624 for my $card (@{$patron->cards()}) {
626 $card->usr($new_patron->id());
628 if(ref($card) and $card->isnew()) {
630 $virtual_id = $card->id();
631 ( $card, $evt ) = _add_card($session,$card);
632 return (undef, $evt) if $evt;
634 #if(ref($patron->card)) { $patron->card($patron->card->id); }
635 if($patron->card() == $virtual_id) {
636 $new_patron->card($card->id());
637 $new_patron->ischanged(1);
640 } elsif( ref($card) and $card->ischanged() ) {
641 $evt = _update_card($session, $card);
642 return (undef, $evt) if $evt;
646 return ( $new_patron, undef );
650 # adds an card to the db and returns the card with new id
652 my( $session, $card ) = @_;
655 $logger->info("Adding new patron card ".$card->barcode);
657 my $id = $session->request(
658 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
659 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
660 $logger->info("Successfully created patron card $id");
663 return ( $card, undef );
667 # returns event on error. returns undef otherwise
669 my( $session, $card ) = @_;
670 $logger->info("Updating patron card ".$card->id);
672 my $stat = $session->request(
673 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
674 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
681 # returns event on error. returns undef otherwise
682 sub _delete_address {
683 my( $session, $address ) = @_;
685 $logger->info("Deleting address ".$address->id." from DB");
687 my $stat = $session->request(
688 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
690 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
696 sub _add_survey_responses {
697 my ($session, $patron, $new_patron) = @_;
699 $logger->info( "Updating survey responses for patron ".$new_patron->id );
701 my $responses = $patron->survey_responses;
705 $_->usr($new_patron->id) for (@$responses);
707 my $evt = $U->simplereq( "open-ils.circ",
708 "open-ils.circ.survey.submit.user_id", $responses );
710 return (undef, $evt) if defined($U->event_code($evt));
714 return ( $new_patron, undef );
718 sub _create_stat_maps {
720 my($session, $user_session, $patron, $new_patron) = @_;
722 my $maps = $patron->stat_cat_entries();
724 for my $map (@$maps) {
726 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
728 if ($map->isdeleted()) {
729 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
731 } elsif ($map->isnew()) {
732 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
737 $map->target_usr($new_patron->id);
740 $logger->info("Updating stat entry with method $method and map $map");
742 my $stat = $session->request($method, $map)->gather(1);
743 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
747 return ($new_patron, undef);
750 sub _create_perm_maps {
752 my($session, $user_session, $patron, $new_patron) = @_;
754 my $maps = $patron->permissions;
756 for my $map (@$maps) {
758 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
759 if ($map->isdeleted()) {
760 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
761 } elsif ($map->isnew()) {
762 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
767 $map->usr($new_patron->id);
769 #warn( "Updating permissions with method $method and session $user_session and map $map" );
770 $logger->info( "Updating permissions with method $method and map $map" );
772 my $stat = $session->request($method, $map)->gather(1);
773 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
777 return ($new_patron, undef);
781 __PACKAGE__->register_method(
782 method => "set_user_work_ous",
783 api_name => "open-ils.actor.user.work_ous.update",
786 sub set_user_work_ous {
792 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
795 my $session = $apputils->start_db_session();
797 for my $map (@$maps) {
799 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
800 if ($map->isdeleted()) {
801 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
802 } elsif ($map->isnew()) {
803 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
807 #warn( "Updating permissions with method $method and session $ses and map $map" );
808 $logger->info( "Updating work_ou map with method $method and map $map" );
810 my $stat = $session->request($method, $map)->gather(1);
811 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
815 $apputils->commit_db_session($session);
817 return scalar(@$maps);
821 __PACKAGE__->register_method(
822 method => "set_user_perms",
823 api_name => "open-ils.actor.user.permissions.update",
832 my $session = $apputils->start_db_session();
834 my( $user_obj, $evt ) = $U->checkses($ses);
837 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
840 $all = 1 if ($user_obj->super_user());
841 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
843 for my $map (@$maps) {
845 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
846 if ($map->isdeleted()) {
847 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
848 } elsif ($map->isnew()) {
849 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
853 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
855 #warn( "Updating permissions with method $method and session $ses and map $map" );
856 $logger->info( "Updating permissions with method $method and map $map" );
858 my $stat = $session->request($method, $map)->gather(1);
859 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
863 $apputils->commit_db_session($session);
865 return scalar(@$maps);
869 sub _create_standing_penalties {
871 my($session, $user_session, $patron, $new_patron) = @_;
873 my $maps = $patron->standing_penalties;
876 for my $map (@$maps) {
878 if ($map->isdeleted()) {
879 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
880 } elsif ($map->isnew()) {
881 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
887 $map->usr($new_patron->id);
889 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
891 my $stat = $session->request($method, $map)->gather(1);
892 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
895 return ($new_patron, undef);
900 __PACKAGE__->register_method(
901 method => "search_username",
902 api_name => "open-ils.actor.user.search.username",
905 sub search_username {
906 my($self, $client, $username) = @_;
907 return new_editor()->search_actor_user({usrname=>$username});
913 __PACKAGE__->register_method(
914 method => "user_retrieve_by_barcode",
915 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
917 sub user_retrieve_by_barcode {
918 my($self, $client, $user_session, $barcode) = @_;
920 $logger->debug("Searching for user with barcode $barcode");
921 my ($user_obj, $evt) = $apputils->checkses($user_session);
924 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
926 "open-ils.cstore.direct.actor.card.search.atomic",
927 { barcode => $barcode }
930 if(!$card || !$card->[0]) {
931 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
935 my $user = flesh_user($card->usr());
937 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
940 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
947 __PACKAGE__->register_method(
948 method => "get_user_by_id",
949 api_name => "open-ils.actor.user.retrieve",);
952 my ($self, $client, $auth, $id) = @_;
953 my $e = new_editor(authtoken=>$auth);
954 return $e->event unless $e->checkauth;
955 my $user = $e->retrieve_actor_user($id)
957 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
963 __PACKAGE__->register_method(
964 method => "get_org_types",
965 api_name => "open-ils.actor.org_types.retrieve",);
969 my($self, $client) = @_;
970 return $org_types if $org_types;
971 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
976 __PACKAGE__->register_method(
977 method => "get_user_ident_types",
978 api_name => "open-ils.actor.user.ident_types.retrieve",
981 sub get_user_ident_types {
982 return $ident_types if $ident_types;
983 return $ident_types =
984 new_editor()->retrieve_all_config_identification_type();
990 __PACKAGE__->register_method(
991 method => "get_org_unit",
992 api_name => "open-ils.actor.org_unit.retrieve",
996 my( $self, $client, $user_session, $org_id ) = @_;
997 my $e = new_editor(authtoken => $user_session);
999 return $e->event unless $e->checkauth;
1000 $org_id = $e->requestor->ws_ou;
1002 my $o = $e->retrieve_actor_org_unit($org_id)
1003 or return $e->event;
1007 __PACKAGE__->register_method(
1008 method => "search_org_unit",
1009 api_name => "open-ils.actor.org_unit_list.search",
1012 sub search_org_unit {
1014 my( $self, $client, $field, $value ) = @_;
1016 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1018 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1019 { $field => $value } );
1025 # build the org tree
1027 __PACKAGE__->register_method(
1028 method => "get_org_tree",
1029 api_name => "open-ils.actor.org_tree.retrieve",
1031 note => "Returns the entire org tree structure",
1035 my( $self, $client) = @_;
1037 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
1038 my $tree = $cache->get_cache('orgtree');
1039 return $tree if $tree;
1041 $tree = new_editor()->search_actor_org_unit(
1043 {"parent_ou" => undef },
1046 flesh_fields => { aou => ['children'] },
1047 order_by => { aou => 'name'}
1052 $cache->put_cache('orgtree', $tree);
1057 # turns an org list into an org tree
1058 sub build_org_tree {
1060 my( $self, $orglist) = @_;
1062 return $orglist unless ref $orglist;
1063 return $$orglist[0] if @$orglist == 1;
1066 $a->ou_type <=> $b->ou_type ||
1067 $a->name cmp $b->name } @$orglist;
1069 for my $org (@list) {
1071 next unless ($org and defined($org->parent_ou));
1072 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1073 next unless $parent;
1075 $parent->children([]) unless defined($parent->children);
1076 push( @{$parent->children}, $org );
1084 __PACKAGE__->register_method(
1085 method => "get_org_descendants",
1086 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1089 # depth is optional. org_unit is the id
1090 sub get_org_descendants {
1091 my( $self, $client, $org_unit, $depth ) = @_;
1092 my $orglist = $apputils->simple_scalar_request(
1094 "open-ils.storage.actor.org_unit.descendants.atomic",
1095 $org_unit, $depth );
1096 return $self->build_org_tree($orglist);
1100 __PACKAGE__->register_method(
1101 method => "get_org_ancestors",
1102 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1105 # depth is optional. org_unit is the id
1106 sub get_org_ancestors {
1107 my( $self, $client, $org_unit, $depth ) = @_;
1108 my $orglist = $apputils->simple_scalar_request(
1110 "open-ils.storage.actor.org_unit.ancestors.atomic",
1111 $org_unit, $depth );
1112 return $self->build_org_tree($orglist);
1116 __PACKAGE__->register_method(
1117 method => "get_standings",
1118 api_name => "open-ils.actor.standings.retrieve"
1123 return $user_standings if $user_standings;
1124 return $user_standings =
1125 $apputils->simple_scalar_request(
1127 "open-ils.cstore.direct.config.standing.search.atomic",
1128 { id => { "!=" => undef } }
1134 __PACKAGE__->register_method(
1135 method => "get_my_org_path",
1136 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1139 sub get_my_org_path {
1140 my( $self, $client, $auth, $org_id ) = @_;
1141 my $e = new_editor(authtoken=>$auth);
1142 return $e->event unless $e->checkauth;
1143 $org_id = $e->requestor->ws_ou unless defined $org_id;
1145 return $apputils->simple_scalar_request(
1147 "open-ils.storage.actor.org_unit.full_path.atomic",
1152 __PACKAGE__->register_method(
1153 method => "patron_adv_search",
1154 api_name => "open-ils.actor.patron.search.advanced" );
1155 sub patron_adv_search {
1156 my( $self, $client, $auth, $search_hash, $search_limit, $search_sort, $include_inactive ) = @_;
1157 my $e = new_editor(authtoken=>$auth);
1158 return $e->event unless $e->checkauth;
1159 return $e->event unless $e->allowed('VIEW_USER');
1160 return $U->storagereq(
1161 "open-ils.storage.actor.user.crazy_search",
1162 $search_hash, $search_limit, $search_sort, $include_inactive);
1168 sub _verify_password {
1169 my($user_session, $password) = @_;
1170 my $user_obj = $apputils->check_user_session($user_session);
1172 #grab the user with password
1173 $user_obj = $apputils->simple_scalar_request(
1175 "open-ils.cstore.direct.actor.user.retrieve",
1178 if($user_obj->passwd eq $password) {
1186 __PACKAGE__->register_method(
1187 method => "update_password",
1188 api_name => "open-ils.actor.user.password.update");
1190 __PACKAGE__->register_method(
1191 method => "update_password",
1192 api_name => "open-ils.actor.user.username.update");
1194 __PACKAGE__->register_method(
1195 method => "update_password",
1196 api_name => "open-ils.actor.user.email.update");
1198 sub update_password {
1199 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1203 my $session = $apputils->start_db_session();
1204 my $user_obj = $apputils->check_user_session($user_session);
1206 #fetch the in-database version so we get the latest xact_id
1207 $user_obj = $session->request(
1208 'open-ils.storage.direct.actor.user.retrieve', $user_obj->id)->gather(1);
1210 if($self->api_name =~ /password/o) {
1212 #make sure they know the current password
1213 if(!_verify_password($user_session, md5_hex($current_password))) {
1214 return OpenILS::Event->new('INCORRECT_PASSWORD');
1217 $logger->debug("update_password setting new password $new_value");
1218 $user_obj->passwd($new_value);
1220 } elsif($self->api_name =~ /username/o) {
1221 my $users = search_username(undef, undef, $new_value);
1222 if( $users and $users->[0] ) {
1223 return OpenILS::Event->new('USERNAME_EXISTS');
1225 $user_obj->usrname($new_value);
1227 } elsif($self->api_name =~ /email/o) {
1228 #warn "Updating email to $new_value\n";
1229 $user_obj->email($new_value);
1233 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1234 return $evt if $evt;
1236 $apputils->commit_db_session($session);
1238 if($user_obj) { return 1; }
1243 __PACKAGE__->register_method(
1244 method => "update_passwd",
1245 api_name => "open-ils.actor.user.password.update");
1247 __PACKAGE__->register_method(
1248 method => "update_passwd",
1249 api_name => "open-ils.actor.user.username.update");
1251 __PACKAGE__->register_method(
1252 method => "update_passwd",
1253 api_name => "open-ils.actor.user.email.update");
1256 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1257 my $e = new_editor(xact=>1, authtoken=>$auth);
1258 return $e->die_event unless $e->checkauth;
1260 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1261 or return $e->die_event;
1262 my $api = $self->api_name;
1264 if( $api =~ /password/o ) {
1266 # make sure the original password matches the in-database password
1267 return OpenILS::Event->new('INCORRECT_PASSWORD')
1268 if md5_hex($orig_pw) ne $db_user->passwd;
1269 $db_user->passwd($new_val);
1273 # if we don't clear the password, the user will be updated with
1274 # a hashed version of the hashed version of their password
1275 $db_user->clear_passwd;
1277 if( $api =~ /username/o ) {
1279 # make sure no one else has this username
1280 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1281 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1282 $db_user->usrname($new_val);
1284 } elsif( $api =~ /email/o ) {
1285 $db_user->email($new_val);
1289 $e->update_actor_user($db_user) or return $e->die_event;
1297 __PACKAGE__->register_method(
1298 method => "check_user_perms",
1299 api_name => "open-ils.actor.user.perm.check",
1300 notes => <<" NOTES");
1301 Takes a login session, user id, an org id, and an array of perm type strings. For each
1302 perm type, if the user does *not* have the given permission it is added
1303 to a list which is returned from the method. If all permissions
1304 are allowed, an empty list is returned
1305 if the logged in user does not match 'user_id', then the logged in user must
1306 have VIEW_PERMISSION priveleges.
1309 sub check_user_perms {
1310 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1312 my( $staff, $evt ) = $apputils->checkses($login_session);
1313 return $evt if $evt;
1315 if($staff->id ne $user_id) {
1316 if( $evt = $apputils->check_perms(
1317 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1323 for my $perm (@$perm_types) {
1324 if($apputils->check_perms($user_id, $org_id, $perm)) {
1325 push @not_allowed, $perm;
1329 return \@not_allowed
1332 __PACKAGE__->register_method(
1333 method => "check_user_perms2",
1334 api_name => "open-ils.actor.user.perm.check.multi_org",
1336 Checks the permissions on a list of perms and orgs for a user
1337 @param authtoken The login session key
1338 @param user_id The id of the user to check
1339 @param orgs The array of org ids
1340 @param perms The array of permission names
1341 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1342 if the logged in user does not match 'user_id', then the logged in user must
1343 have VIEW_PERMISSION priveleges.
1346 sub check_user_perms2 {
1347 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1349 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1350 $authtoken, $user_id, 'VIEW_PERMISSION' );
1351 return $evt if $evt;
1354 for my $org (@$orgs) {
1355 for my $perm (@$perms) {
1356 if($apputils->check_perms($user_id, $org, $perm)) {
1357 push @not_allowed, [ $org, $perm ];
1362 return \@not_allowed
1366 __PACKAGE__->register_method(
1367 method => 'check_user_perms3',
1368 api_name => 'open-ils.actor.user.perm.highest_org',
1370 Returns the highest org unit id at which a user has a given permission
1371 If the requestor does not match the target user, the requestor must have
1372 'VIEW_PERMISSION' rights at the home org unit of the target user
1373 @param authtoken The login session key
1374 @param userid The id of the user in question
1375 @param perm The permission to check
1376 @return The org unit highest in the org tree within which the user has
1377 the requested permission
1380 sub check_user_perms3 {
1381 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1383 my( $staff, $target, $org, $evt );
1385 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1386 $authtoken, $userid, 'VIEW_PERMISSION' );
1387 return $evt if $evt;
1389 my $tree = $self->get_org_tree();
1390 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1394 sub _find_highest_perm_org {
1395 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1396 my $org = $apputils->find_org($org_tree, $start_org );
1400 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1402 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1408 __PACKAGE__->register_method(
1409 method => 'check_user_perms4',
1410 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1412 Returns the highest org unit id at which a user has a given permission
1413 If the requestor does not match the target user, the requestor must have
1414 'VIEW_PERMISSION' rights at the home org unit of the target user
1415 @param authtoken The login session key
1416 @param userid The id of the user in question
1417 @param perms An array of perm names to check
1418 @return An array of orgId's representing the org unit
1419 highest in the org tree within which the user has the requested permission
1420 The arrah of orgId's has matches the order of the perms array
1423 sub check_user_perms4 {
1424 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1426 my( $staff, $target, $org, $evt );
1428 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1429 $authtoken, $userid, 'VIEW_PERMISSION' );
1430 return $evt if $evt;
1433 return [] unless ref($perms);
1434 my $tree = $self->get_org_tree();
1436 for my $p (@$perms) {
1437 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1445 __PACKAGE__->register_method(
1446 method => "user_fines_summary",
1447 api_name => "open-ils.actor.user.fines.summary",
1448 notes => <<" NOTES");
1449 Returns a short summary of the users total open fines, excluding voided fines
1450 Params are login_session, user_id
1451 Returns a 'mous' object.
1454 sub user_fines_summary {
1455 my( $self, $client, $auth, $user_id ) = @_;
1456 my $e = new_editor(authtoken=>$auth);
1457 return $e->event unless $e->checkauth;
1458 my $user = $e->retrieve_actor_user($user_id)
1459 or return $e->event;
1461 if( $user_id ne $e->requestor->id ) {
1462 return $e->event unless
1463 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1466 # run this inside a transaction to prevent replication delay errors
1467 my $ses = $U->start_db_session();
1468 my $s = $ses->request(
1469 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1470 $U->rollback_db_session($ses);
1477 __PACKAGE__->register_method(
1478 method => "user_transactions",
1479 api_name => "open-ils.actor.user.transactions",
1480 notes => <<" NOTES");
1481 Returns a list of open user transactions (mbts objects);
1482 Params are login_session, user_id
1483 Optional third parameter is the transactions type. defaults to all
1486 __PACKAGE__->register_method(
1487 method => "user_transactions",
1488 api_name => "open-ils.actor.user.transactions.have_charge",
1489 notes => <<" NOTES");
1490 Returns a list of all open user transactions (mbts objects) that have an initial charge
1491 Params are login_session, user_id
1492 Optional third parameter is the transactions type. defaults to all
1495 __PACKAGE__->register_method(
1496 method => "user_transactions",
1497 api_name => "open-ils.actor.user.transactions.have_balance",
1498 notes => <<" NOTES");
1499 Returns a list of all open user transactions (mbts objects) that have a balance
1500 Params are login_session, user_id
1501 Optional third parameter is the transactions type. defaults to all
1504 __PACKAGE__->register_method(
1505 method => "user_transactions",
1506 api_name => "open-ils.actor.user.transactions.fleshed",
1507 notes => <<" NOTES");
1508 Returns an object/hash of transaction, circ, title where transaction = an open
1509 user transactions (mbts objects), circ is the attached circluation, and title
1510 is the title the circ points to
1511 Params are login_session, user_id
1512 Optional third parameter is the transactions type. defaults to all
1515 __PACKAGE__->register_method(
1516 method => "user_transactions",
1517 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1518 notes => <<" NOTES");
1519 Returns an object/hash of transaction, circ, title where transaction = an open
1520 user transactions that has an initial charge (mbts objects), circ is the
1521 attached circluation, and title is the title the circ points to
1522 Params are login_session, user_id
1523 Optional third parameter is the transactions type. defaults to all
1526 __PACKAGE__->register_method(
1527 method => "user_transactions",
1528 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1529 notes => <<" NOTES");
1530 Returns an object/hash of transaction, circ, title where transaction = an open
1531 user transaction that has a balance (mbts objects), circ is the attached
1532 circluation, and title is the title the circ points to
1533 Params are login_session, user_id
1534 Optional third parameter is the transaction type. defaults to all
1537 __PACKAGE__->register_method(
1538 method => "user_transactions",
1539 api_name => "open-ils.actor.user.transactions.count",
1540 notes => <<" NOTES");
1541 Returns an object/hash of transaction, circ, title where transaction = an open
1542 user transactions (mbts objects), circ is the attached circluation, and title
1543 is the title the circ points to
1544 Params are login_session, user_id
1545 Optional third parameter is the transactions type. defaults to all
1548 __PACKAGE__->register_method(
1549 method => "user_transactions",
1550 api_name => "open-ils.actor.user.transactions.have_charge.count",
1551 notes => <<" NOTES");
1552 Returns an object/hash of transaction, circ, title where transaction = an open
1553 user transactions that has an initial charge (mbts objects), circ is the
1554 attached circluation, and title is the title the circ points to
1555 Params are login_session, user_id
1556 Optional third parameter is the transactions type. defaults to all
1559 __PACKAGE__->register_method(
1560 method => "user_transactions",
1561 api_name => "open-ils.actor.user.transactions.have_balance.count",
1562 notes => <<" NOTES");
1563 Returns an object/hash of transaction, circ, title where transaction = an open
1564 user transaction that has a balance (mbts objects), circ is the attached
1565 circluation, and title is the title the circ points to
1566 Params are login_session, user_id
1567 Optional third parameter is the transaction type. defaults to all
1570 __PACKAGE__->register_method(
1571 method => "user_transactions",
1572 api_name => "open-ils.actor.user.transactions.have_balance.total",
1573 notes => <<" NOTES");
1574 Returns an object/hash of transaction, circ, title where transaction = an open
1575 user transaction that has a balance (mbts objects), circ is the attached
1576 circluation, and title is the title the circ points to
1577 Params are login_session, user_id
1578 Optional third parameter is the transaction type. defaults to all
1583 sub user_transactions {
1584 my( $self, $client, $login_session, $user_id, $type ) = @_;
1586 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1587 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1588 return $evt if $evt;
1590 my $api = $self->api_name();
1594 if(defined($type)) { @xact = (xact_type => $type);
1596 } else { @xact = (); }
1599 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1600 ->run($login_session => $user_id => $type);
1602 if($api =~ /have_charge/o) {
1604 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1606 } elsif($api =~ /have_balance/o) {
1608 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1611 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1615 if($api =~ /total/o) {
1617 for my $t (@$trans) {
1618 $total += $t->balance_owed;
1621 $logger->debug("Total balance owed by user $user_id: $total");
1625 if($api =~ /count/o) { return scalar @$trans; }
1626 if($api !~ /fleshed/o) { return $trans; }
1629 for my $t (@$trans) {
1631 if( $t->xact_type ne 'circulation' ) {
1632 push @resp, {transaction => $t};
1636 my $circ = $apputils->simple_scalar_request(
1638 "open-ils.cstore.direct.action.circulation.retrieve",
1643 my $title = $apputils->simple_scalar_request(
1645 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1646 $circ->target_copy );
1650 my $u = OpenILS::Utils::ModsParser->new();
1651 $u->start_mods_batch($title->marc());
1652 my $mods = $u->finish_mods_batch();
1653 $mods->doc_id($title->id) if $mods;
1655 push @resp, {transaction => $t, circ => $circ, record => $mods };
1663 __PACKAGE__->register_method(
1664 method => "user_transaction_retrieve",
1665 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1667 notes => <<" NOTES");
1668 Returns a fleshedtransaction record
1670 __PACKAGE__->register_method(
1671 method => "user_transaction_retrieve",
1672 api_name => "open-ils.actor.user.transaction.retrieve",
1674 notes => <<" NOTES");
1675 Returns a transaction record
1677 sub user_transaction_retrieve {
1678 my( $self, $client, $login_session, $bill_id ) = @_;
1680 # XXX I think I'm deprecated... make sure
1682 my $trans = $apputils->simple_scalar_request(
1684 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1688 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1689 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1690 return $evt if $evt;
1692 my $api = $self->api_name();
1693 if($api !~ /fleshed/o) { return $trans; }
1695 if( $trans->xact_type ne 'circulation' ) {
1696 $logger->debug("Returning non-circ transaction");
1697 return {transaction => $trans};
1700 my $circ = $apputils->simple_scalar_request(
1702 "open-ils..direct.action.circulation.retrieve",
1705 return {transaction => $trans} unless $circ;
1706 $logger->debug("Found the circ transaction");
1708 my $title = $apputils->simple_scalar_request(
1710 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1711 $circ->target_copy );
1713 return {transaction => $trans, circ => $circ } unless $title;
1714 $logger->debug("Found the circ title");
1718 my $u = OpenILS::Utils::ModsParser->new();
1719 $u->start_mods_batch($title->marc());
1720 $mods = $u->finish_mods_batch();
1722 if ($title->id == OILS_PRECAT_RECORD) {
1723 my $copy = $apputils->simple_scalar_request(
1725 "open-ils.cstore.direct.asset.copy.retrieve",
1726 $circ->target_copy );
1728 $mods = new Fieldmapper::metabib::virtual_record;
1729 $mods->doc_id(OILS_PRECAT_RECORD);
1730 $mods->title($copy->dummy_title);
1731 $mods->author($copy->dummy_author);
1735 $logger->debug("MODSized the circ title");
1737 return {transaction => $trans, circ => $circ, record => $mods };
1741 __PACKAGE__->register_method(
1742 method => "hold_request_count",
1743 api_name => "open-ils.actor.user.hold_requests.count",
1745 notes => <<" NOTES");
1746 Returns hold ready/total counts
1748 sub hold_request_count {
1749 my( $self, $client, $login_session, $userid ) = @_;
1751 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1752 $login_session, $userid, 'VIEW_HOLD' );
1753 return $evt if $evt;
1756 my $holds = $apputils->simple_scalar_request(
1758 "open-ils.cstore.direct.action.hold_request.search.atomic",
1761 fulfillment_time => {"=" => undef },
1762 cancel_time => undef,
1767 for my $h (@$holds) {
1768 next unless $h->capture_time and $h->current_copy;
1770 my $copy = $apputils->simple_scalar_request(
1772 "open-ils.cstore.direct.asset.copy.retrieve",
1776 if ($copy and $copy->status == 8) {
1781 return { total => scalar(@$holds), ready => scalar(@ready) };
1785 __PACKAGE__->register_method(
1786 method => "checkedout_count",
1787 api_name => "open-ils.actor.user.checked_out.count__",
1789 notes => <<" NOTES");
1790 Returns a transaction record
1794 sub checkedout_count {
1795 my( $self, $client, $login_session, $userid ) = @_;
1797 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1798 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1799 return $evt if $evt;
1801 my $circs = $apputils->simple_scalar_request(
1803 "open-ils.cstore.direct.action.circulation.search.atomic",
1804 { usr => $userid, stop_fines => undef }
1805 #{ usr => $userid, checkin_time => {"=" => undef } }
1808 my $parser = DateTime::Format::ISO8601->new;
1811 for my $c (@$circs) {
1812 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1813 my $due = $due_dt->epoch;
1815 if ($due < DateTime->today->epoch) {
1820 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1824 __PACKAGE__->register_method(
1825 method => "checked_out",
1826 api_name => "open-ils.actor.user.checked_out",
1829 Returns a structure of circulations objects sorted by
1830 out, overdue, lost, claims_returned, long_overdue.
1831 A list of IDs are returned of each type.
1832 lost, long_overdue, and claims_returned circ will not
1833 be "finished" (there is an outstanding balance or some
1834 other pending action on the circ).
1836 The .count method also includes a 'total' field which
1837 sums all "open" circs
1841 __PACKAGE__->register_method(
1842 method => "checked_out",
1843 api_name => "open-ils.actor.user.checked_out.count",
1845 signature => q/@see open-ils.actor.user.checked_out/
1849 my( $self, $conn, $auth, $userid ) = @_;
1851 my $e = new_editor(authtoken=>$auth);
1852 return $e->event unless $e->checkauth;
1854 if( $userid ne $e->requestor->id ) {
1855 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1858 my $count = $self->api_name =~ /count/;
1859 return _checked_out( $count, $e, $userid );
1863 my( $iscount, $e, $userid ) = @_;
1866 my $meth = 'open-ils.storage.actor.user.checked_out';
1867 $meth = "$meth.count" if $iscount;
1868 return $U->storagereq($meth, $userid);
1870 # XXX Old code - moved to storage
1871 #------------------------------------------------------------------------------
1872 #------------------------------------------------------------------------------
1873 my $circs = $e->search_action_circulation(
1874 { usr => $userid, checkin_time => undef });
1876 my $parser = DateTime::Format::ISO8601->new;
1878 # split the circs up into overdue and not-overdue circs
1880 for my $c (@$circs) {
1881 if( $c->due_date ) {
1882 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1883 my $due = $due_dt->epoch;
1884 if ($due < DateTime->today->epoch) {
1894 my( @open, @od, @lost, @cr, @lo );
1896 while (my $c = shift(@out)) {
1897 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1898 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1899 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1900 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1903 while (my $c = shift(@overdue)) {
1904 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1905 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1906 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1907 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1912 total => @open + @od + @lost + @cr + @lo,
1913 out => scalar(@open),
1914 overdue => scalar(@od),
1915 lost => scalar(@lost),
1916 claims_returned => scalar(@cr),
1917 long_overdue => scalar(@lo)
1925 claims_returned => \@cr,
1926 long_overdue => \@lo
1931 sub _checked_out_WHAT {
1932 my( $iscount, $e, $userid ) = @_;
1934 my $circs = $e->search_action_circulation(
1935 { usr => $userid, stop_fines => undef });
1937 my $mcircs = $e->search_action_circulation(
1940 checkin_time => undef,
1941 xact_finish => undef,
1945 push( @$circs, @$mcircs );
1947 my $parser = DateTime::Format::ISO8601->new;
1949 # split the circs up into overdue and not-overdue circs
1951 for my $c (@$circs) {
1952 if( $c->due_date ) {
1953 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1954 my $due = $due_dt->epoch;
1955 if ($due < DateTime->today->epoch) {
1956 push @overdue, $c->id;
1965 # grab all of the lost, claims-returned, and longoverdue circs
1966 #my $open = $e->search_action_circulation(
1967 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1970 # these items have stop_fines, but no xact_finish, so money
1971 # is owed on them and they have not been checked in
1972 my $open = $e->search_action_circulation(
1975 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1976 xact_finish => undef,
1977 checkin_time => undef,
1982 my( @lost, @cr, @lo );
1983 for my $c (@$open) {
1984 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1985 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1986 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1992 total => @$circs + @lost + @cr + @lo,
1993 out => scalar(@out),
1994 overdue => scalar(@overdue),
1995 lost => scalar(@lost),
1996 claims_returned => scalar(@cr),
1997 long_overdue => scalar(@lo)
2003 overdue => \@overdue,
2005 claims_returned => \@cr,
2006 long_overdue => \@lo
2012 __PACKAGE__->register_method(
2013 method => "checked_in_with_fines",
2014 api_name => "open-ils.actor.user.checked_in_with_fines",
2016 signature => q/@see open-ils.actor.user.checked_out/
2018 sub checked_in_with_fines {
2019 my( $self, $conn, $auth, $userid ) = @_;
2021 my $e = new_editor(authtoken=>$auth);
2022 return $e->event unless $e->checkauth;
2024 if( $userid ne $e->requestor->id ) {
2025 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2028 # money is owed on these items and they are checked in
2029 my $open = $e->search_action_circulation(
2032 xact_finish => undef,
2033 checkin_time => { "!=" => undef },
2038 my( @lost, @cr, @lo );
2039 for my $c (@$open) {
2040 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2041 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2042 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2047 claims_returned => \@cr,
2048 long_overdue => \@lo
2060 __PACKAGE__->register_method(
2061 method => "user_transaction_history",
2062 api_name => "open-ils.actor.user.transactions.history",
2064 notes => <<" NOTES");
2065 Returns a list of billable transaction ids for a user, optionally by type
2067 __PACKAGE__->register_method(
2068 method => "user_transaction_history",
2069 api_name => "open-ils.actor.user.transactions.history.have_charge",
2071 notes => <<" NOTES");
2072 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2074 __PACKAGE__->register_method(
2075 method => "user_transaction_history",
2076 api_name => "open-ils.actor.user.transactions.history.have_balance",
2078 notes => <<" NOTES");
2079 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2081 __PACKAGE__->register_method(
2082 method => "user_transaction_history",
2083 api_name => "open-ils.actor.user.transactions.history.still_open",
2085 notes => <<" NOTES");
2086 Returns a list of billable transaction ids for a user that are not finished
2088 __PACKAGE__->register_method(
2089 method => "user_transaction_history",
2090 api_name => "open-ils.actor.user.transactions.history.have_bill",
2092 notes => <<" NOTES");
2093 Returns a list of billable transaction ids for a user that has billings
2099 sub _user_transaction_history {
2100 my( $self, $client, $login_session, $user_id, $type ) = @_;
2102 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2103 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2104 return $evt if $evt;
2106 my $api = $self->api_name();
2111 @xact = (xact_type => $type) if(defined($type));
2112 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2113 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2115 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2117 my $trans = $apputils->simple_scalar_request(
2119 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2120 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2122 return [ map { $_->id } @$trans ];
2126 =head SEE APPUTILS.PM
2131 for my $x (@xacts) {
2132 my $s = new Fieldmapper::money::billable_transaction_summary;
2135 $s->xact_start( $x->xact_start );
2136 $s->xact_finish( $x->xact_finish );
2140 for my $b (@{ $x->billings }) {
2141 next if ($U->is_true($b->voided));
2142 $to += ($b->amount * 100);
2143 $lb ||= $b->billing_ts;
2144 if ($b->billing_ts ge $lb) {
2145 $lb = $b->billing_ts;
2146 $s->last_billing_note($b->note);
2147 $s->last_billing_ts($b->billing_ts);
2148 $s->last_billing_type($b->billing_type);
2152 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2156 for my $p (@{ $x->payments }) {
2157 next if ($U->is_true($p->voided));
2158 $tp += ($p->amount * 100);
2159 $lp ||= $p->payment_ts;
2160 if ($p->payment_ts ge $lp) {
2161 $lp = $p->payment_ts;
2162 $s->last_payment_note($p->note);
2163 $s->last_payment_ts($p->payment_ts);
2164 $s->last_payment_type($p->payment_type);
2167 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2169 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2171 $s->xact_type( 'grocery' ) if ($x->grocery);
2172 $s->xact_type( 'circulation' ) if ($x->circulation);
2181 sub user_transaction_history {
2182 my( $self, $conn, $auth, $userid, $type ) = @_;
2184 # run inside of a transaction to prevent replication delays
2185 my $e = new_editor(xact=>1, authtoken=>$auth);
2186 return $e->die_event unless $e->checkauth;
2188 if( $e->requestor->id ne $userid ) {
2189 return $e->die_event
2190 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2193 my $api = $self->api_name;
2194 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2196 my @xacts = @{ $e->search_money_billable_transaction(
2197 [ { usr => $userid, @xact_finish },
2199 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2200 order_by => { mbt => 'xact_start DESC' },
2208 #my @mbts = _make_mbts( @xacts );
2209 my @mbts = $U->make_mbts( @xacts );
2211 if(defined($type)) {
2212 @mbts = grep { $_->xact_type eq $type } @mbts;
2215 if($api =~ /have_balance/o) {
2216 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2219 if($api =~ /have_charge/o) {
2220 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2223 if($api =~ /have_bill/o) {
2224 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2232 __PACKAGE__->register_method(
2233 method => "user_perms",
2234 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2236 notes => <<" NOTES");
2237 Returns a list of permissions
2240 my( $self, $client, $authtoken, $user ) = @_;
2242 my( $staff, $evt ) = $apputils->checkses($authtoken);
2243 return $evt if $evt;
2245 $user ||= $staff->id;
2247 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2251 return $apputils->simple_scalar_request(
2253 "open-ils.storage.permission.user_perms.atomic",
2257 __PACKAGE__->register_method(
2258 method => "retrieve_perms",
2259 api_name => "open-ils.actor.permissions.retrieve",
2260 notes => <<" NOTES");
2261 Returns a list of permissions
2263 sub retrieve_perms {
2264 my( $self, $client ) = @_;
2265 return $apputils->simple_scalar_request(
2267 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2268 { id => { '!=' => undef } }
2272 __PACKAGE__->register_method(
2273 method => "retrieve_groups",
2274 api_name => "open-ils.actor.groups.retrieve",
2275 notes => <<" NOTES");
2276 Returns a list of user groupss
2278 sub retrieve_groups {
2279 my( $self, $client ) = @_;
2280 return new_editor()->retrieve_all_permission_grp_tree();
2283 __PACKAGE__->register_method(
2284 method => "retrieve_org_address",
2285 api_name => "open-ils.actor.org_unit.address.retrieve",
2286 notes => <<' NOTES');
2287 Returns an org_unit address by ID
2288 @param An org_address ID
2290 sub retrieve_org_address {
2291 my( $self, $client, $id ) = @_;
2292 return $apputils->simple_scalar_request(
2294 "open-ils.cstore.direct.actor.org_address.retrieve",
2299 __PACKAGE__->register_method(
2300 method => "retrieve_groups_tree",
2301 api_name => "open-ils.actor.groups.tree.retrieve",
2302 notes => <<" NOTES");
2303 Returns a list of user groups
2305 sub retrieve_groups_tree {
2306 my( $self, $client ) = @_;
2307 return new_editor()->search_permission_grp_tree(
2312 flesh_fields => { pgt => ["children"] },
2313 order_by => { pgt => 'name'}
2320 # turns an org list into an org tree
2322 sub build_group_tree {
2324 my( $self, $grplist) = @_;
2326 return $grplist unless (
2327 ref($grplist) and @$grplist > 1 );
2329 my @list = sort { $a->name cmp $b->name } @$grplist;
2332 for my $grp (@list) {
2334 if ($grp and !defined($grp->parent)) {
2338 my ($parent) = grep { $_->id == $grp->parent} @list;
2340 $parent->children([]) unless defined($parent->children);
2341 push( @{$parent->children}, $grp );
2349 __PACKAGE__->register_method(
2350 method => "add_user_to_groups",
2351 api_name => "open-ils.actor.user.set_groups",
2352 notes => <<" NOTES");
2353 Adds a user to one or more permission groups
2356 sub add_user_to_groups {
2357 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2359 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2360 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2361 return $evt if $evt;
2363 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2364 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2365 return $evt if $evt;
2367 $apputils->simplereq(
2369 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2371 for my $group (@$groups) {
2372 my $link = Fieldmapper::permission::usr_grp_map->new;
2374 $link->usr($userid);
2376 my $id = $apputils->simplereq(
2378 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2384 __PACKAGE__->register_method(
2385 method => "get_user_perm_groups",
2386 api_name => "open-ils.actor.user.get_groups",
2387 notes => <<" NOTES");
2388 Retrieve a user's permission groups.
2392 sub get_user_perm_groups {
2393 my( $self, $client, $authtoken, $userid ) = @_;
2395 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2396 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2397 return $evt if $evt;
2399 return $apputils->simplereq(
2401 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2404 __PACKAGE__->register_method(
2405 method => "get_user_work_ous",
2406 api_name => "open-ils.actor.user.get_work_ous",
2407 notes => <<" NOTES");
2408 Retrieve a user's work org units.
2412 sub get_user_work_ous {
2413 my( $self, $client, $authtoken, $userid ) = @_;
2415 my( $requestor, $evt ) = $apputils->checksesperm( $authtoken, 'ASSIGN_WORK_ORG_UNIT' );
2416 return $evt if $evt;
2418 return $apputils->simplereq(
2420 'open-ils.cstore.direct.permission.usr_work_ou_map.search.atomic', { usr => $userid } );
2425 __PACKAGE__->register_method (
2426 method => 'register_workstation',
2427 api_name => 'open-ils.actor.workstation.register.override',
2428 signature => q/@see open-ils.actor.workstation.register/);
2430 __PACKAGE__->register_method (
2431 method => 'register_workstation',
2432 api_name => 'open-ils.actor.workstation.register',
2434 Registers a new workstion in the system
2435 @param authtoken The login session key
2436 @param name The name of the workstation id
2437 @param owner The org unit that owns this workstation
2438 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2439 if the name is already in use.
2442 sub _register_workstation {
2443 my( $self, $connection, $authtoken, $name, $owner ) = @_;
2444 my( $requestor, $evt ) = $U->checkses($authtoken);
2445 return $evt if $evt;
2446 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
2447 return $evt if $evt;
2449 my $ws = $U->cstorereq(
2450 'open-ils.cstore.direct.actor.workstation.search', { name => $name } );
2451 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
2453 $ws = Fieldmapper::actor::workstation->new;
2454 $ws->owning_lib($owner);
2457 my $id = $U->storagereq(
2458 'open-ils.storage.direct.actor.workstation.create', $ws );
2459 return $U->DB_UPDATE_FAILED($ws) unless $id;
2465 sub register_workstation {
2466 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2468 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2469 return $e->event unless $e->checkauth;
2470 return $e->event unless $e->allowed('REGISTER_WORKSTATION'); # XXX rely on editor perms
2471 my $existing = $e->search_actor_workstation({name => $name});
2474 if( $self->api_name =~ /override/o ) {
2475 return $e->event unless $e->allowed('DELETE_WORKSTATION'); # XXX rely on editor perms
2476 return $e->event unless $e->delete_actor_workstation($$existing[0]);
2478 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2482 my $ws = Fieldmapper::actor::workstation->new;
2483 $ws->owning_lib($owner);
2485 $e->create_actor_workstation($ws) or return $e->event;
2487 return $ws->id; # note: editor sets the id on the new object for us
2491 __PACKAGE__->register_method (
2492 method => 'fetch_patron_note',
2493 api_name => 'open-ils.actor.note.retrieve.all',
2495 Returns a list of notes for a given user
2496 Requestor must have VIEW_USER permission if pub==false and
2497 @param authtoken The login session key
2498 @param args Hash of params including
2499 patronid : the patron's id
2500 pub : true if retrieving only public notes
2504 sub fetch_patron_note {
2505 my( $self, $conn, $authtoken, $args ) = @_;
2506 my $patronid = $$args{patronid};
2508 my($reqr, $evt) = $U->checkses($authtoken);
2509 return $evt if $evt;
2512 ($patron, $evt) = $U->fetch_user($patronid);
2513 return $evt if $evt;
2516 if( $patronid ne $reqr->id ) {
2517 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2518 return $evt if $evt;
2520 return $U->cstorereq(
2521 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2522 { usr => $patronid, pub => 't' } );
2525 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2526 return $evt if $evt;
2528 return $U->cstorereq(
2529 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2532 __PACKAGE__->register_method (
2533 method => 'create_user_note',
2534 api_name => 'open-ils.actor.note.create',
2536 Creates a new note for the given user
2537 @param authtoken The login session key
2538 @param note The note object
2541 sub create_user_note {
2542 my( $self, $conn, $authtoken, $note ) = @_;
2543 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2544 return $e->die_event unless $e->checkauth;
2546 my $user = $e->retrieve_actor_user($note->usr)
2547 or return $e->die_event;
2549 return $e->die_event unless
2550 $e->allowed('UPDATE_USER',$user->home_ou);
2552 $note->creator($e->requestor->id);
2553 $e->create_actor_usr_note($note) or return $e->die_event;
2559 __PACKAGE__->register_method (
2560 method => 'delete_user_note',
2561 api_name => 'open-ils.actor.note.delete',
2563 Deletes a note for the given user
2564 @param authtoken The login session key
2565 @param noteid The note id
2568 sub delete_user_note {
2569 my( $self, $conn, $authtoken, $noteid ) = @_;
2571 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2572 return $e->die_event unless $e->checkauth;
2573 my $note = $e->retrieve_actor_usr_note($noteid)
2574 or return $e->die_event;
2575 my $user = $e->retrieve_actor_user($note->usr)
2576 or return $e->die_event;
2577 return $e->die_event unless
2578 $e->allowed('UPDATE_USER', $user->home_ou);
2580 $e->delete_actor_usr_note($note) or return $e->die_event;
2586 __PACKAGE__->register_method (
2587 method => 'update_user_note',
2588 api_name => 'open-ils.actor.note.update',
2590 @param authtoken The login session key
2591 @param note The note
2595 sub update_user_note {
2596 my( $self, $conn, $auth, $note ) = @_;
2597 my $e = new_editor(authtoken=>$auth, xact=>1);
2598 return $e->event unless $e->checkauth;
2599 my $patron = $e->retrieve_actor_user($note->usr)
2600 or return $e->event;
2601 return $e->event unless
2602 $e->allowed('UPDATE_USER', $patron->home_ou);
2603 $e->update_actor_user_note($note)
2604 or return $e->event;
2612 __PACKAGE__->register_method (
2613 method => 'create_closed_date',
2614 api_name => 'open-ils.actor.org_unit.closed_date.create',
2616 Creates a new closing entry for the given org_unit
2617 @param authtoken The login session key
2618 @param note The closed_date object
2621 sub create_closed_date {
2622 my( $self, $conn, $authtoken, $cd ) = @_;
2624 my( $user, $evt ) = $U->checkses($authtoken);
2625 return $evt if $evt;
2627 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2628 return $evt if $evt;
2630 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2632 my $id = $U->storagereq(
2633 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2634 return $U->DB_UPDATE_FAILED($cd) unless $id;
2639 __PACKAGE__->register_method (
2640 method => 'delete_closed_date',
2641 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2643 Deletes a closing entry for the given org_unit
2644 @param authtoken The login session key
2645 @param noteid The close_date id
2648 sub delete_closed_date {
2649 my( $self, $conn, $authtoken, $cd ) = @_;
2651 my( $user, $evt ) = $U->checkses($authtoken);
2652 return $evt if $evt;
2655 ($cd_obj, $evt) = fetch_closed_date($cd);
2656 return $evt if $evt;
2658 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2659 return $evt if $evt;
2661 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2663 my $stat = $U->storagereq(
2664 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2665 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2670 __PACKAGE__->register_method(
2671 method => 'usrname_exists',
2672 api_name => 'open-ils.actor.username.exists',
2674 Returns 1 if the requested username exists, returns 0 otherwise
2678 sub usrname_exists {
2679 my( $self, $conn, $auth, $usrname ) = @_;
2680 my $e = new_editor(authtoken=>$auth);
2681 return $e->event unless $e->checkauth;
2682 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2683 return $$a[0] if $a and @$a;
2687 __PACKAGE__->register_method(
2688 method => 'barcode_exists',
2689 api_name => 'open-ils.actor.barcode.exists',
2691 Returns 1 if the requested barcode exists, returns 0 otherwise
2695 sub barcode_exists {
2696 my( $self, $conn, $auth, $barcode ) = @_;
2697 my $e = new_editor(authtoken=>$auth);
2698 return $e->event unless $e->checkauth;
2699 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2700 return $$a[0] if $a and @$a;
2705 __PACKAGE__->register_method(
2706 method => 'retrieve_net_levels',
2707 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2710 sub retrieve_net_levels {
2711 my( $self, $conn, $auth ) = @_;
2712 my $e = new_editor(authtoken=>$auth);
2713 return $e->event unless $e->checkauth;
2714 return $e->retrieve_all_config_net_access_level();
2718 __PACKAGE__->register_method(
2719 method => 'fetch_org_by_shortname',
2720 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2722 sub fetch_org_by_shortname {
2723 my( $self, $conn, $sname ) = @_;
2724 my $e = new_editor();
2725 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2726 return $e->event unless $org;
2731 __PACKAGE__->register_method(
2732 method => 'session_home_lib',
2733 api_name => 'open-ils.actor.session.home_lib',
2736 sub session_home_lib {
2737 my( $self, $conn, $auth ) = @_;
2738 my $e = new_editor(authtoken=>$auth);
2739 return undef unless $e->checkauth;
2740 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2741 return $org->shortname;
2744 __PACKAGE__->register_method(
2745 method => 'session_safe_token',
2746 api_name => 'open-ils.actor.session.safe_token',
2748 Returns a hashed session ID that is safe for export to the world.
2749 This safe token will expire after 1 hour of non-use.
2750 @param auth Active authentication token
2754 sub session_safe_token {
2755 my( $self, $conn, $auth ) = @_;
2756 my $e = new_editor(authtoken=>$auth);
2757 return undef unless $e->checkauth;
2759 my $safe_token = md5_hex($auth);
2761 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2763 # Add more like the following if needed...
2765 "safe-token-home_lib-shortname-$safe_token",
2766 $e->retrieve_actor_org_unit(
2767 $e->requestor->home_ou
2776 __PACKAGE__->register_method(
2777 method => 'safe_token_home_lib',
2778 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2780 Returns the home library shortname from the session
2781 asscociated with a safe token from generated by
2782 open-ils.actor.session.safe_token.
2783 @param safe_token Active safe token
2787 sub safe_token_home_lib {
2788 my( $self, $conn, $safe_token ) = @_;
2790 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2791 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2796 __PACKAGE__->register_method(
2797 method => 'slim_tree',
2798 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2801 my $tree = new_editor()->search_actor_org_unit(
2803 {"parent_ou" => undef },
2806 flesh_fields => { aou => ['children'] },
2807 order_by => { aou => 'name'},
2808 select => { aou => ["id","shortname", "name"]},
2813 return trim_tree($tree);
2819 return undef unless $tree;
2821 code => $tree->shortname,
2822 name => $tree->name,
2824 if( $tree->children and @{$tree->children} ) {
2825 $htree->{children} = [];
2826 for my $c (@{$tree->children}) {
2827 push( @{$htree->{children}}, trim_tree($c) );
2835 __PACKAGE__->register_method(
2836 method => "update_penalties",
2837 api_name => "open-ils.actor.user.penalties.update");
2838 sub update_penalties {
2839 my( $self, $conn, $auth, $userid ) = @_;
2840 my $e = new_editor(authtoken=>$auth);
2841 return $e->event unless $e->checkauth;
2842 $U->update_patron_penalties(
2844 patronid => $userid,
2851 __PACKAGE__->register_method(
2852 method => "user_retrieve_fleshed_by_id",
2853 api_name => "open-ils.actor.user.fleshed.retrieve",);
2855 sub user_retrieve_fleshed_by_id {
2856 my( $self, $client, $auth, $user_id, $fields ) = @_;
2857 my $e = new_editor(authtoken => $auth);
2858 return $e->event unless $e->checkauth;
2860 if( $e->requestor->id != $user_id ) {
2861 return $e->event unless $e->allowed('VIEW_USER');
2867 "standing_penalties",
2871 "stat_cat_entries" ];
2872 return new_flesh_user($user_id, $fields, $e);
2876 sub new_flesh_user {
2879 my $fields = shift || [];
2880 my $e = shift || new_editor(xact=>1);
2882 my $user = $e->retrieve_actor_user(
2887 "flesh_fields" => { "au" => $fields }
2890 ) or return $e->event;
2893 if( grep { $_ eq 'addresses' } @$fields ) {
2895 $user->addresses([]) unless @{$user->addresses};
2897 if( ref $user->billing_address ) {
2898 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2899 push( @{$user->addresses}, $user->billing_address );
2903 if( ref $user->mailing_address ) {
2904 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2905 push( @{$user->addresses}, $user->mailing_address );
2911 $user->clear_passwd();
2918 __PACKAGE__->register_method(
2919 method => "user_retrieve_parts",
2920 api_name => "open-ils.actor.user.retrieve.parts",);
2922 sub user_retrieve_parts {
2923 my( $self, $client, $auth, $user_id, $fields ) = @_;
2924 my $e = new_editor(authtoken => $auth);
2925 return $e->event unless $e->checkauth;
2926 if( $e->requestor->id != $user_id ) {
2927 return $e->event unless $e->allowed('VIEW_USER');
2930 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2931 push(@resp, $user->$_()) for(@$fields);