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, $conn, $authtoken, $name, $owner ) = @_;
2445 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2446 return $e->die_event unless $e->checkauth;
2447 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2448 my $existing = $e->search_actor_workstation({name => $name})->[0];
2452 if( $self->api_name =~ /override/o ) {
2453 # workstation with the given name exists.
2455 if($owner ne $existing->owning_lib) {
2456 # if necessary, update the owning_lib of the workstation
2458 $logger->info("changing owning lib of workstation ".$existing->id.
2459 " from ".$existing->owning_lib." to $owner");
2460 return $e->die_event unless
2461 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2463 $existing->owning_lib($owner);
2464 return $e->die_event unless $e->update_actor_workstation($existing);
2470 "attempt to register an existing workstation. returning existing ID");
2473 return $existing->id;
2476 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2480 my $ws = Fieldmapper::actor::workstation->new;
2481 $ws->owning_lib($owner);
2483 $e->create_actor_workstation($ws) or return $e->die_event;
2485 return $ws->id; # note: editor sets the id on the new object for us
2489 __PACKAGE__->register_method (
2490 method => 'fetch_patron_note',
2491 api_name => 'open-ils.actor.note.retrieve.all',
2493 Returns a list of notes for a given user
2494 Requestor must have VIEW_USER permission if pub==false and
2495 @param authtoken The login session key
2496 @param args Hash of params including
2497 patronid : the patron's id
2498 pub : true if retrieving only public notes
2502 sub fetch_patron_note {
2503 my( $self, $conn, $authtoken, $args ) = @_;
2504 my $patronid = $$args{patronid};
2506 my($reqr, $evt) = $U->checkses($authtoken);
2507 return $evt if $evt;
2510 ($patron, $evt) = $U->fetch_user($patronid);
2511 return $evt if $evt;
2514 if( $patronid ne $reqr->id ) {
2515 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2516 return $evt if $evt;
2518 return $U->cstorereq(
2519 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2520 { usr => $patronid, pub => 't' } );
2523 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2524 return $evt if $evt;
2526 return $U->cstorereq(
2527 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2530 __PACKAGE__->register_method (
2531 method => 'create_user_note',
2532 api_name => 'open-ils.actor.note.create',
2534 Creates a new note for the given user
2535 @param authtoken The login session key
2536 @param note The note object
2539 sub create_user_note {
2540 my( $self, $conn, $authtoken, $note ) = @_;
2541 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2542 return $e->die_event unless $e->checkauth;
2544 my $user = $e->retrieve_actor_user($note->usr)
2545 or return $e->die_event;
2547 return $e->die_event unless
2548 $e->allowed('UPDATE_USER',$user->home_ou);
2550 $note->creator($e->requestor->id);
2551 $e->create_actor_usr_note($note) or return $e->die_event;
2557 __PACKAGE__->register_method (
2558 method => 'delete_user_note',
2559 api_name => 'open-ils.actor.note.delete',
2561 Deletes a note for the given user
2562 @param authtoken The login session key
2563 @param noteid The note id
2566 sub delete_user_note {
2567 my( $self, $conn, $authtoken, $noteid ) = @_;
2569 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2570 return $e->die_event unless $e->checkauth;
2571 my $note = $e->retrieve_actor_usr_note($noteid)
2572 or return $e->die_event;
2573 my $user = $e->retrieve_actor_user($note->usr)
2574 or return $e->die_event;
2575 return $e->die_event unless
2576 $e->allowed('UPDATE_USER', $user->home_ou);
2578 $e->delete_actor_usr_note($note) or return $e->die_event;
2584 __PACKAGE__->register_method (
2585 method => 'update_user_note',
2586 api_name => 'open-ils.actor.note.update',
2588 @param authtoken The login session key
2589 @param note The note
2593 sub update_user_note {
2594 my( $self, $conn, $auth, $note ) = @_;
2595 my $e = new_editor(authtoken=>$auth, xact=>1);
2596 return $e->event unless $e->checkauth;
2597 my $patron = $e->retrieve_actor_user($note->usr)
2598 or return $e->event;
2599 return $e->event unless
2600 $e->allowed('UPDATE_USER', $patron->home_ou);
2601 $e->update_actor_user_note($note)
2602 or return $e->event;
2610 __PACKAGE__->register_method (
2611 method => 'create_closed_date',
2612 api_name => 'open-ils.actor.org_unit.closed_date.create',
2614 Creates a new closing entry for the given org_unit
2615 @param authtoken The login session key
2616 @param note The closed_date object
2619 sub create_closed_date {
2620 my( $self, $conn, $authtoken, $cd ) = @_;
2622 my( $user, $evt ) = $U->checkses($authtoken);
2623 return $evt if $evt;
2625 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2626 return $evt if $evt;
2628 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2630 my $id = $U->storagereq(
2631 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2632 return $U->DB_UPDATE_FAILED($cd) unless $id;
2637 __PACKAGE__->register_method (
2638 method => 'delete_closed_date',
2639 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2641 Deletes a closing entry for the given org_unit
2642 @param authtoken The login session key
2643 @param noteid The close_date id
2646 sub delete_closed_date {
2647 my( $self, $conn, $authtoken, $cd ) = @_;
2649 my( $user, $evt ) = $U->checkses($authtoken);
2650 return $evt if $evt;
2653 ($cd_obj, $evt) = fetch_closed_date($cd);
2654 return $evt if $evt;
2656 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2657 return $evt if $evt;
2659 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2661 my $stat = $U->storagereq(
2662 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2663 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2668 __PACKAGE__->register_method(
2669 method => 'usrname_exists',
2670 api_name => 'open-ils.actor.username.exists',
2672 Returns 1 if the requested username exists, returns 0 otherwise
2676 sub usrname_exists {
2677 my( $self, $conn, $auth, $usrname ) = @_;
2678 my $e = new_editor(authtoken=>$auth);
2679 return $e->event unless $e->checkauth;
2680 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2681 return $$a[0] if $a and @$a;
2685 __PACKAGE__->register_method(
2686 method => 'barcode_exists',
2687 api_name => 'open-ils.actor.barcode.exists',
2689 Returns 1 if the requested barcode exists, returns 0 otherwise
2693 sub barcode_exists {
2694 my( $self, $conn, $auth, $barcode ) = @_;
2695 my $e = new_editor(authtoken=>$auth);
2696 return $e->event unless $e->checkauth;
2697 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2698 return $$a[0] if $a and @$a;
2703 __PACKAGE__->register_method(
2704 method => 'retrieve_net_levels',
2705 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2708 sub retrieve_net_levels {
2709 my( $self, $conn, $auth ) = @_;
2710 my $e = new_editor(authtoken=>$auth);
2711 return $e->event unless $e->checkauth;
2712 return $e->retrieve_all_config_net_access_level();
2716 __PACKAGE__->register_method(
2717 method => 'fetch_org_by_shortname',
2718 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2720 sub fetch_org_by_shortname {
2721 my( $self, $conn, $sname ) = @_;
2722 my $e = new_editor();
2723 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2724 return $e->event unless $org;
2729 __PACKAGE__->register_method(
2730 method => 'session_home_lib',
2731 api_name => 'open-ils.actor.session.home_lib',
2734 sub session_home_lib {
2735 my( $self, $conn, $auth ) = @_;
2736 my $e = new_editor(authtoken=>$auth);
2737 return undef unless $e->checkauth;
2738 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2739 return $org->shortname;
2742 __PACKAGE__->register_method(
2743 method => 'session_safe_token',
2744 api_name => 'open-ils.actor.session.safe_token',
2746 Returns a hashed session ID that is safe for export to the world.
2747 This safe token will expire after 1 hour of non-use.
2748 @param auth Active authentication token
2752 sub session_safe_token {
2753 my( $self, $conn, $auth ) = @_;
2754 my $e = new_editor(authtoken=>$auth);
2755 return undef unless $e->checkauth;
2757 my $safe_token = md5_hex($auth);
2759 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2761 # Add more like the following if needed...
2763 "safe-token-home_lib-shortname-$safe_token",
2764 $e->retrieve_actor_org_unit(
2765 $e->requestor->home_ou
2774 __PACKAGE__->register_method(
2775 method => 'safe_token_home_lib',
2776 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2778 Returns the home library shortname from the session
2779 asscociated with a safe token from generated by
2780 open-ils.actor.session.safe_token.
2781 @param safe_token Active safe token
2785 sub safe_token_home_lib {
2786 my( $self, $conn, $safe_token ) = @_;
2788 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2789 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2794 __PACKAGE__->register_method(
2795 method => 'slim_tree',
2796 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2799 my $tree = new_editor()->search_actor_org_unit(
2801 {"parent_ou" => undef },
2804 flesh_fields => { aou => ['children'] },
2805 order_by => { aou => 'name'},
2806 select => { aou => ["id","shortname", "name"]},
2811 return trim_tree($tree);
2817 return undef unless $tree;
2819 code => $tree->shortname,
2820 name => $tree->name,
2822 if( $tree->children and @{$tree->children} ) {
2823 $htree->{children} = [];
2824 for my $c (@{$tree->children}) {
2825 push( @{$htree->{children}}, trim_tree($c) );
2833 __PACKAGE__->register_method(
2834 method => "update_penalties",
2835 api_name => "open-ils.actor.user.penalties.update");
2836 sub update_penalties {
2837 my( $self, $conn, $auth, $userid ) = @_;
2838 my $e = new_editor(authtoken=>$auth);
2839 return $e->event unless $e->checkauth;
2840 $U->update_patron_penalties(
2842 patronid => $userid,
2849 __PACKAGE__->register_method(
2850 method => "user_retrieve_fleshed_by_id",
2851 api_name => "open-ils.actor.user.fleshed.retrieve",);
2853 sub user_retrieve_fleshed_by_id {
2854 my( $self, $client, $auth, $user_id, $fields ) = @_;
2855 my $e = new_editor(authtoken => $auth);
2856 return $e->event unless $e->checkauth;
2858 if( $e->requestor->id != $user_id ) {
2859 return $e->event unless $e->allowed('VIEW_USER');
2865 "standing_penalties",
2869 "stat_cat_entries" ];
2870 return new_flesh_user($user_id, $fields, $e);
2874 sub new_flesh_user {
2877 my $fields = shift || [];
2878 my $e = shift || new_editor(xact=>1);
2880 my $user = $e->retrieve_actor_user(
2885 "flesh_fields" => { "au" => $fields }
2888 ) or return $e->event;
2891 if( grep { $_ eq 'addresses' } @$fields ) {
2893 $user->addresses([]) unless @{$user->addresses};
2895 if( ref $user->billing_address ) {
2896 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2897 push( @{$user->addresses}, $user->billing_address );
2901 if( ref $user->mailing_address ) {
2902 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2903 push( @{$user->addresses}, $user->mailing_address );
2909 $user->clear_passwd();
2916 __PACKAGE__->register_method(
2917 method => "user_retrieve_parts",
2918 api_name => "open-ils.actor.user.retrieve.parts",);
2920 sub user_retrieve_parts {
2921 my( $self, $client, $auth, $user_id, $fields ) = @_;
2922 my $e = new_editor(authtoken => $auth);
2923 return $e->event unless $e->checkauth;
2924 if( $e->requestor->id != $user_id ) {
2925 return $e->event unless $e->allowed('VIEW_USER');
2928 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2929 push(@resp, $user->$_()) for(@$fields);