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/;
19 use OpenSRF::Utils::SettingsClient;
21 use OpenSRF::Utils::Cache;
23 use OpenSRF::Utils::JSON;
25 use DateTime::Format::ISO8601;
26 use OpenILS::Const qw/:const/;
28 use OpenILS::Application::Actor::Container;
29 use OpenILS::Application::Actor::ClosedDates;
31 use OpenILS::Utils::CStoreEditor qw/:funcs/;
33 use OpenILS::Application::Actor::UserGroups;
35 OpenILS::Application::Actor::Container->initialize();
36 OpenILS::Application::Actor::UserGroups->initialize();
37 OpenILS::Application::Actor::ClosedDates->initialize();
40 my $apputils = "OpenILS::Application::AppUtils";
43 sub _d { warn "Patron:\n" . Dumper(shift()); }
48 my $set_user_settings;
51 __PACKAGE__->register_method(
52 method => "set_user_settings",
53 api_name => "open-ils.actor.patron.settings.update",
55 sub set_user_settings {
56 my( $self, $client, $user_session, $uid, $settings ) = @_;
58 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
60 my( $staff, $user, $evt ) =
61 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
65 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
67 $_->[1]->{value} = OpenSRF::Utils::JSON->perl2JSON($_->[1]->{value}) for @params;
69 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
71 my $ses = $U->start_db_session();
72 my $stat = $ses->request(
73 'open-ils.storage.direct.actor.user_setting.batch.merge', @params )->gather(1);
74 $U->commit_db_session($ses);
81 __PACKAGE__->register_method(
82 method => "set_ou_settings",
83 api_name => "open-ils.actor.org_unit.settings.update",
86 my( $self, $client, $user_session, $ouid, $settings ) = @_;
88 my( $staff, $evt ) = $apputils->checkses( $user_session );
90 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_SETTING' );
94 for my $set (keys %$settings) {
96 my $json = OpenSRF::Utils::JSON->perl2JSON($$settings{$set});
97 $logger->activity("updating org_unit.setting: $ouid : $set : $json");
100 { org_unit => $ouid, name => $set },
101 { value => $json } );
104 my $ses = $U->start_db_session();
105 my $stat = $ses->request(
106 'open-ils.storage.direct.actor.org_unit_setting.merge', @params )->gather(1);
107 $U->commit_db_session($ses);
113 my $fetch_user_settings;
114 my $fetch_ou_settings;
116 __PACKAGE__->register_method(
117 method => "user_settings",
118 api_name => "open-ils.actor.patron.settings.retrieve",
121 my( $self, $client, $user_session, $uid, $setting ) = @_;
123 my( $staff, $user, $evt ) =
124 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
127 $logger->debug("User " . $staff->id . " fetching user $uid\n");
128 my $s = $apputils->simplereq(
130 'open-ils.cstore.direct.actor.user_setting.search.atomic', { usr => $uid } );
132 my $settings = { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
134 return $$settings{$setting} if $setting;
140 __PACKAGE__->register_method(
141 method => "ou_settings",
142 api_name => "open-ils.actor.org_unit.settings.retrieve",
145 my( $self, $client, $ouid ) = @_;
147 $logger->info("Fetching org unit settings for org $ouid");
149 my $s = $apputils->simplereq(
151 'open-ils.cstore.direct.actor.org_unit_setting.search.atomic', {org_unit => $ouid});
153 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
158 __PACKAGE__->register_method(
159 api_name => 'open-ils.actor.ou_setting.ancestor_default',
160 method => 'ou_ancestor_setting',
163 # ------------------------------------------------------------------
164 # Attempts to find the org setting value for a given org. if not
165 # found at the requested org, searches up the org tree until it
166 # finds a parent that has the requested setting.
167 # when found, returns { org => $id, value => $value }
168 # otherwise, returns NULL
169 # ------------------------------------------------------------------
170 sub ou_ancestor_setting {
171 my( $self, $client, $orgid, $name ) = @_;
172 return $U->ou_ancestor_setting($orgid, $name);
178 __PACKAGE__->register_method (
179 method => "ou_setting_delete",
180 api_name => 'open-ils.actor.org_setting.delete',
182 Deletes a specific org unit setting for a specific location
183 @param authtoken The login session key
184 @param orgid The org unit whose setting we're changing
185 @param setting The name of the setting to delete
186 @return True value on success.
190 sub ou_setting_delete {
191 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
192 my( $reqr, $evt) = $U->checkses($authtoken);
194 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
197 my $id = $U->cstorereq(
198 'open-ils.cstore.direct.actor.org_unit_setting.id_list',
199 { name => $setting, org_unit => $orgid } );
201 $logger->debug("Retrieved setting $id in org unit setting delete");
203 my $s = $U->cstorereq(
204 'open-ils.cstore.direct.actor.org_unit_setting.delete', $id );
206 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
220 __PACKAGE__->register_method(
221 method => "update_patron",
222 api_name => "open-ils.actor.patron.update",);
225 my( $self, $client, $user_session, $patron ) = @_;
227 my $session = $apputils->start_db_session();
231 $logger->info("Creating new patron...") if $patron->isnew;
232 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
234 my( $user_obj, $evt ) = $U->checkses($user_session);
237 $evt = check_group_perm($session, $user_obj, $patron);
241 # $new_patron is the patron in progress. $patron is the original patron
242 # passed in with the method. new_patron will change as the components
243 # of patron are added/updated.
247 # unflesh the real items on the patron
248 $patron->card( $patron->card->id ) if(ref($patron->card));
249 $patron->billing_address( $patron->billing_address->id )
250 if(ref($patron->billing_address));
251 $patron->mailing_address( $patron->mailing_address->id )
252 if(ref($patron->mailing_address));
254 # create/update the patron first so we can use his id
255 if($patron->isnew()) {
256 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
258 } else { $new_patron = $patron; }
260 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
263 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
266 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
269 # re-update the patron if anything has happened to him during this process
270 if($new_patron->ischanged()) {
271 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
275 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
278 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
281 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
284 $logger->activity("user ".$user_obj->id." updating/creating user ".$new_patron->id);
287 if(!$patron->isnew) {
288 $opatron = new_editor()->retrieve_actor_user($new_patron->id);
291 $apputils->commit_db_session($session);
292 my $fuser = flesh_user($new_patron->id());
295 # Log the new and old patron for investigation
296 $logger->info("$user_session updating patron object. orig patron object = ".
297 OpenSRF::Utils::JSON->perl2JSON($opatron). " |||| new patron = ".OpenSRF::Utils::JSON->perl2JSON($fuser));
307 return new_flesh_user($id, [
310 "standing_penalties",
314 "stat_cat_entries" ] );
322 # clone and clear stuff that would break the database
326 my $new_patron = $patron->clone;
328 $new_patron->clear_billing_address();
329 $new_patron->clear_mailing_address();
330 $new_patron->clear_addresses();
331 $new_patron->clear_card();
332 $new_patron->clear_cards();
333 $new_patron->clear_id();
334 $new_patron->clear_isnew();
335 $new_patron->clear_ischanged();
336 $new_patron->clear_isdeleted();
337 $new_patron->clear_stat_cat_entries();
338 $new_patron->clear_permissions();
339 $new_patron->clear_standing_penalties();
349 my $user_obj = shift;
351 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
352 return (undef, $evt) if $evt;
354 my $ex = $session->request(
355 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
357 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
360 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
362 my $id = $session->request(
363 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
364 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
366 $logger->info("Successfully created new user [$id] in DB");
368 return ( $session->request(
369 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
373 sub check_group_perm {
374 my( $session, $requestor, $patron ) = @_;
377 # first let's see if the requestor has
378 # priveleges to update this user in any way
379 if( ! $patron->isnew ) {
380 my $p = $session->request(
381 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
383 # If we are the requestor (trying to update our own account)
384 # and we are not trying to change our profile, we're good
385 if( $p->id == $requestor->id and
386 $p->profile == $patron->profile ) {
391 $evt = group_perm_failed($session, $requestor, $p);
395 # They are allowed to edit this patron.. can they put the
396 # patron into the group requested?
397 $evt = group_perm_failed($session, $requestor, $patron);
403 sub group_perm_failed {
404 my( $session, $requestor, $patron ) = @_;
408 my $grpid = $patron->profile;
412 $logger->debug("user update looking for group perm for group $grpid");
413 $grp = $session->request(
414 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
415 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
417 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
419 $logger->info("user update checking perm $perm on user ".
420 $requestor->id." for update/create on user username=".$patron->usrname);
422 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
430 my( $session, $patron, $user_obj, $noperm) = @_;
432 $logger->info("Updating patron ".$patron->id." in DB");
437 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
438 return (undef, $evt) if $evt;
441 # update the password by itself to avoid the password protection magic
442 if( $patron->passwd ) {
443 my $s = $session->request(
444 'open-ils.storage.direct.actor.user.remote_update',
445 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
446 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
447 $patron->clear_passwd;
450 if(!$patron->ident_type) {
451 $patron->clear_ident_type;
452 $patron->clear_ident_value;
455 $evt = verify_last_xact($session, $patron);
456 return (undef, $evt) if $evt;
458 my $stat = $session->request(
459 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
460 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
465 sub verify_last_xact {
466 my( $session, $patron ) = @_;
467 return undef unless $patron->id and $patron->id > 0;
468 my $p = $session->request(
469 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
470 my $xact = $p->last_xact_id;
471 return undef unless $xact;
472 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
473 return OpenILS::Event->new('XACT_COLLISION')
474 if $xact != $patron->last_xact_id;
479 sub _check_dup_ident {
480 my( $session, $patron ) = @_;
482 return undef unless $patron->ident_value;
485 ident_type => $patron->ident_type,
486 ident_value => $patron->ident_value,
489 $logger->debug("patron update searching for dup ident values: " .
490 $patron->ident_type . ':' . $patron->ident_value);
492 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
494 my $dups = $session->request(
495 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
498 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
505 sub _add_update_addresses {
509 my $new_patron = shift;
513 my $current_id; # id of the address before creation
515 for my $address (@{$patron->addresses()}) {
517 next unless ref $address;
518 $current_id = $address->id();
520 if( $patron->billing_address() and
521 $patron->billing_address() == $current_id ) {
522 $logger->info("setting billing addr to $current_id");
523 $new_patron->billing_address($address->id());
524 $new_patron->ischanged(1);
527 if( $patron->mailing_address() and
528 $patron->mailing_address() == $current_id ) {
529 $new_patron->mailing_address($address->id());
530 $logger->info("setting mailing addr to $current_id");
531 $new_patron->ischanged(1);
535 if($address->isnew()) {
537 $address->usr($new_patron->id());
539 ($address, $evt) = _add_address($session,$address);
540 return (undef, $evt) if $evt;
542 # we need to get the new id
543 if( $patron->billing_address() and
544 $patron->billing_address() == $current_id ) {
545 $new_patron->billing_address($address->id());
546 $logger->info("setting billing addr to $current_id");
547 $new_patron->ischanged(1);
550 if( $patron->mailing_address() and
551 $patron->mailing_address() == $current_id ) {
552 $new_patron->mailing_address($address->id());
553 $logger->info("setting mailing addr to $current_id");
554 $new_patron->ischanged(1);
557 } elsif($address->ischanged() ) {
559 ($address, $evt) = _update_address($session, $address);
560 return (undef, $evt) if $evt;
562 } elsif($address->isdeleted() ) {
564 if( $address->id() == $new_patron->mailing_address() ) {
565 $new_patron->clear_mailing_address();
566 ($new_patron, $evt) = _update_patron($session, $new_patron);
567 return (undef, $evt) if $evt;
570 if( $address->id() == $new_patron->billing_address() ) {
571 $new_patron->clear_billing_address();
572 ($new_patron, $evt) = _update_patron($session, $new_patron);
573 return (undef, $evt) if $evt;
576 $evt = _delete_address($session, $address);
577 return (undef, $evt) if $evt;
581 return ( $new_patron, undef );
585 # adds an address to the db and returns the address with new id
587 my($session, $address) = @_;
588 $address->clear_id();
590 $logger->info("Creating new address at street ".$address->street1);
592 # put the address into the database
593 my $id = $session->request(
594 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
595 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
598 return ($address, undef);
602 sub _update_address {
603 my( $session, $address ) = @_;
605 $logger->info("Updating address ".$address->id." in the DB");
607 my $stat = $session->request(
608 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
610 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
611 return ($address, undef);
616 sub _add_update_cards {
620 my $new_patron = shift;
624 my $virtual_id; #id of the card before creation
625 for my $card (@{$patron->cards()}) {
627 $card->usr($new_patron->id());
629 if(ref($card) and $card->isnew()) {
631 $virtual_id = $card->id();
632 ( $card, $evt ) = _add_card($session,$card);
633 return (undef, $evt) if $evt;
635 #if(ref($patron->card)) { $patron->card($patron->card->id); }
636 if($patron->card() == $virtual_id) {
637 $new_patron->card($card->id());
638 $new_patron->ischanged(1);
641 } elsif( ref($card) and $card->ischanged() ) {
642 $evt = _update_card($session, $card);
643 return (undef, $evt) if $evt;
647 return ( $new_patron, undef );
651 # adds an card to the db and returns the card with new id
653 my( $session, $card ) = @_;
656 $logger->info("Adding new patron card ".$card->barcode);
658 my $id = $session->request(
659 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
660 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
661 $logger->info("Successfully created patron card $id");
664 return ( $card, undef );
668 # returns event on error. returns undef otherwise
670 my( $session, $card ) = @_;
671 $logger->info("Updating patron card ".$card->id);
673 my $stat = $session->request(
674 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
675 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
682 # returns event on error. returns undef otherwise
683 sub _delete_address {
684 my( $session, $address ) = @_;
686 $logger->info("Deleting address ".$address->id." from DB");
688 my $stat = $session->request(
689 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
691 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
697 sub _add_survey_responses {
698 my ($session, $patron, $new_patron) = @_;
700 $logger->info( "Updating survey responses for patron ".$new_patron->id );
702 my $responses = $patron->survey_responses;
706 $_->usr($new_patron->id) for (@$responses);
708 my $evt = $U->simplereq( "open-ils.circ",
709 "open-ils.circ.survey.submit.user_id", $responses );
711 return (undef, $evt) if defined($U->event_code($evt));
715 return ( $new_patron, undef );
719 sub _create_stat_maps {
721 my($session, $user_session, $patron, $new_patron) = @_;
723 my $maps = $patron->stat_cat_entries();
725 for my $map (@$maps) {
727 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
729 if ($map->isdeleted()) {
730 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
732 } elsif ($map->isnew()) {
733 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
738 $map->target_usr($new_patron->id);
741 $logger->info("Updating stat entry with method $method and map $map");
743 my $stat = $session->request($method, $map)->gather(1);
744 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
748 return ($new_patron, undef);
751 sub _create_perm_maps {
753 my($session, $user_session, $patron, $new_patron) = @_;
755 my $maps = $patron->permissions;
757 for my $map (@$maps) {
759 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
760 if ($map->isdeleted()) {
761 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
762 } elsif ($map->isnew()) {
763 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
768 $map->usr($new_patron->id);
770 #warn( "Updating permissions with method $method and session $user_session and map $map" );
771 $logger->info( "Updating permissions with method $method and map $map" );
773 my $stat = $session->request($method, $map)->gather(1);
774 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
778 return ($new_patron, undef);
782 __PACKAGE__->register_method(
783 method => "set_user_work_ous",
784 api_name => "open-ils.actor.user.work_ous.update",
787 sub set_user_work_ous {
793 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
796 my $session = $apputils->start_db_session();
798 for my $map (@$maps) {
800 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
801 if ($map->isdeleted()) {
802 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
803 } elsif ($map->isnew()) {
804 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
808 #warn( "Updating permissions with method $method and session $ses and map $map" );
809 $logger->info( "Updating work_ou map with method $method and map $map" );
811 my $stat = $session->request($method, $map)->gather(1);
812 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
816 $apputils->commit_db_session($session);
818 return scalar(@$maps);
822 __PACKAGE__->register_method(
823 method => "set_user_perms",
824 api_name => "open-ils.actor.user.permissions.update",
833 my $session = $apputils->start_db_session();
835 my( $user_obj, $evt ) = $U->checkses($ses);
838 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
841 $all = 1 if ($user_obj->super_user());
842 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
844 for my $map (@$maps) {
846 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
847 if ($map->isdeleted()) {
848 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
849 } elsif ($map->isnew()) {
850 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
854 next if (!$all || !grep { $_->perm eq $map->perm and $_->grantable == 1 and $_->depth <= $map->depth } @$perms);
856 #warn( "Updating permissions with method $method and session $ses and map $map" );
857 $logger->info( "Updating permissions with method $method and map $map" );
859 my $stat = $session->request($method, $map)->gather(1);
860 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
864 $apputils->commit_db_session($session);
866 return scalar(@$maps);
870 sub _create_standing_penalties {
872 my($session, $user_session, $patron, $new_patron) = @_;
874 my $maps = $patron->standing_penalties;
877 for my $map (@$maps) {
879 if ($map->isdeleted()) {
880 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
881 } elsif ($map->isnew()) {
882 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
888 $map->usr($new_patron->id);
890 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
892 my $stat = $session->request($method, $map)->gather(1);
893 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
896 return ($new_patron, undef);
901 __PACKAGE__->register_method(
902 method => "search_username",
903 api_name => "open-ils.actor.user.search.username",
906 sub search_username {
907 my($self, $client, $username) = @_;
908 return new_editor()->search_actor_user({usrname=>$username});
914 __PACKAGE__->register_method(
915 method => "user_retrieve_by_barcode",
916 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
918 sub user_retrieve_by_barcode {
919 my($self, $client, $user_session, $barcode) = @_;
921 $logger->debug("Searching for user with barcode $barcode");
922 my ($user_obj, $evt) = $apputils->checkses($user_session);
925 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
927 "open-ils.cstore.direct.actor.card.search.atomic",
928 { barcode => $barcode }
931 if(!$card || !$card->[0]) {
932 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
936 my $user = flesh_user($card->usr());
938 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
941 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
948 __PACKAGE__->register_method(
949 method => "get_user_by_id",
950 api_name => "open-ils.actor.user.retrieve",);
953 my ($self, $client, $auth, $id) = @_;
954 my $e = new_editor(authtoken=>$auth);
955 return $e->event unless $e->checkauth;
956 my $user = $e->retrieve_actor_user($id)
958 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
964 __PACKAGE__->register_method(
965 method => "get_org_types",
966 api_name => "open-ils.actor.org_types.retrieve",);
970 my($self, $client) = @_;
971 return $org_types if $org_types;
972 return $org_types = new_editor()->retrieve_all_actor_org_unit_type();
977 __PACKAGE__->register_method(
978 method => "get_user_ident_types",
979 api_name => "open-ils.actor.user.ident_types.retrieve",
982 sub get_user_ident_types {
983 return $ident_types if $ident_types;
984 return $ident_types =
985 new_editor()->retrieve_all_config_identification_type();
991 __PACKAGE__->register_method(
992 method => "get_org_unit",
993 api_name => "open-ils.actor.org_unit.retrieve",
997 my( $self, $client, $user_session, $org_id ) = @_;
998 my $e = new_editor(authtoken => $user_session);
1000 return $e->event unless $e->checkauth;
1001 $org_id = $e->requestor->ws_ou;
1003 my $o = $e->retrieve_actor_org_unit($org_id)
1004 or return $e->event;
1008 __PACKAGE__->register_method(
1009 method => "search_org_unit",
1010 api_name => "open-ils.actor.org_unit_list.search",
1013 sub search_org_unit {
1015 my( $self, $client, $field, $value ) = @_;
1017 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1019 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1020 { $field => $value } );
1026 # build the org tree
1028 __PACKAGE__->register_method(
1029 method => "get_org_tree",
1030 api_name => "open-ils.actor.org_tree.retrieve",
1032 note => "Returns the entire org tree structure",
1036 my( $self, $client) = @_;
1038 $cache = OpenSRF::Utils::Cache->new("global", 0) unless $cache;
1039 my $tree = $cache->get_cache('orgtree');
1040 return $tree if $tree;
1042 $tree = new_editor()->search_actor_org_unit(
1044 {"parent_ou" => undef },
1047 flesh_fields => { aou => ['children'] },
1048 order_by => { aou => 'name'}
1053 $cache->put_cache('orgtree', $tree);
1058 # turns an org list into an org tree
1059 sub build_org_tree {
1061 my( $self, $orglist) = @_;
1063 return $orglist unless ref $orglist;
1064 return $$orglist[0] if @$orglist == 1;
1067 $a->ou_type <=> $b->ou_type ||
1068 $a->name cmp $b->name } @$orglist;
1070 for my $org (@list) {
1072 next unless ($org and defined($org->parent_ou));
1073 my ($parent) = grep { $_->id == $org->parent_ou } @list;
1074 next unless $parent;
1076 $parent->children([]) unless defined($parent->children);
1077 push( @{$parent->children}, $org );
1085 __PACKAGE__->register_method(
1086 method => "get_org_descendants",
1087 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1090 # depth is optional. org_unit is the id
1091 sub get_org_descendants {
1092 my( $self, $client, $org_unit, $depth ) = @_;
1093 my $orglist = $apputils->simple_scalar_request(
1095 "open-ils.storage.actor.org_unit.descendants.atomic",
1096 $org_unit, $depth );
1097 return $self->build_org_tree($orglist);
1101 __PACKAGE__->register_method(
1102 method => "get_org_ancestors",
1103 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1106 # depth is optional. org_unit is the id
1107 sub get_org_ancestors {
1108 my( $self, $client, $org_unit, $depth ) = @_;
1109 my $orglist = $apputils->simple_scalar_request(
1111 "open-ils.storage.actor.org_unit.ancestors.atomic",
1112 $org_unit, $depth );
1113 return $self->build_org_tree($orglist);
1117 __PACKAGE__->register_method(
1118 method => "get_standings",
1119 api_name => "open-ils.actor.standings.retrieve"
1124 return $user_standings if $user_standings;
1125 return $user_standings =
1126 $apputils->simple_scalar_request(
1128 "open-ils.cstore.direct.config.standing.search.atomic",
1129 { id => { "!=" => undef } }
1135 __PACKAGE__->register_method(
1136 method => "get_my_org_path",
1137 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1140 sub get_my_org_path {
1141 my( $self, $client, $auth, $org_id ) = @_;
1142 my $e = new_editor(authtoken=>$auth);
1143 return $e->event unless $e->checkauth;
1144 $org_id = $e->requestor->ws_ou unless defined $org_id;
1146 return $apputils->simple_scalar_request(
1148 "open-ils.storage.actor.org_unit.full_path.atomic",
1153 __PACKAGE__->register_method(
1154 method => "patron_adv_search",
1155 api_name => "open-ils.actor.patron.search.advanced" );
1156 sub patron_adv_search {
1157 my( $self, $client, $auth, $search_hash,
1158 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1160 my $e = new_editor(authtoken=>$auth);
1161 return $e->event unless $e->checkauth;
1162 return $e->event unless $e->allowed('VIEW_USER');
1163 return $U->storagereq(
1164 "open-ils.storage.actor.user.crazy_search", $search_hash,
1165 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1171 sub _verify_password {
1172 my($user_session, $password) = @_;
1173 my $user_obj = $apputils->check_user_session($user_session);
1175 #grab the user with password
1176 $user_obj = $apputils->simple_scalar_request(
1178 "open-ils.cstore.direct.actor.user.retrieve",
1181 if($user_obj->passwd eq $password) {
1189 __PACKAGE__->register_method(
1190 method => "update_password",
1191 api_name => "open-ils.actor.user.password.update");
1193 __PACKAGE__->register_method(
1194 method => "update_password",
1195 api_name => "open-ils.actor.user.username.update");
1197 __PACKAGE__->register_method(
1198 method => "update_password",
1199 api_name => "open-ils.actor.user.email.update");
1201 sub update_password {
1202 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1206 my $session = $apputils->start_db_session();
1207 my $user_obj = $apputils->check_user_session($user_session);
1209 #fetch the in-database version so we get the latest xact_id
1210 $user_obj = $session->request(
1211 'open-ils.storage.direct.actor.user.retrieve', $user_obj->id)->gather(1);
1213 if($self->api_name =~ /password/o) {
1215 #make sure they know the current password
1216 if(!_verify_password($user_session, md5_hex($current_password))) {
1217 return OpenILS::Event->new('INCORRECT_PASSWORD');
1220 $logger->debug("update_password setting new password $new_value");
1221 $user_obj->passwd($new_value);
1223 } elsif($self->api_name =~ /username/o) {
1224 my $users = search_username(undef, undef, $new_value);
1225 if( $users and $users->[0] ) {
1226 return OpenILS::Event->new('USERNAME_EXISTS');
1228 $user_obj->usrname($new_value);
1230 } elsif($self->api_name =~ /email/o) {
1231 #warn "Updating email to $new_value\n";
1232 $user_obj->email($new_value);
1236 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj, 1);
1237 return $evt if $evt;
1239 $apputils->commit_db_session($session);
1241 if($user_obj) { return 1; }
1246 __PACKAGE__->register_method(
1247 method => "update_passwd",
1248 api_name => "open-ils.actor.user.password.update");
1250 __PACKAGE__->register_method(
1251 method => "update_passwd",
1252 api_name => "open-ils.actor.user.username.update");
1254 __PACKAGE__->register_method(
1255 method => "update_passwd",
1256 api_name => "open-ils.actor.user.email.update");
1259 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1260 my $e = new_editor(xact=>1, authtoken=>$auth);
1261 return $e->die_event unless $e->checkauth;
1263 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1264 or return $e->die_event;
1265 my $api = $self->api_name;
1267 if( $api =~ /password/o ) {
1269 # make sure the original password matches the in-database password
1270 return OpenILS::Event->new('INCORRECT_PASSWORD')
1271 if md5_hex($orig_pw) ne $db_user->passwd;
1272 $db_user->passwd($new_val);
1276 # if we don't clear the password, the user will be updated with
1277 # a hashed version of the hashed version of their password
1278 $db_user->clear_passwd;
1280 if( $api =~ /username/o ) {
1282 # make sure no one else has this username
1283 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1284 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1285 $db_user->usrname($new_val);
1287 } elsif( $api =~ /email/o ) {
1288 $db_user->email($new_val);
1292 $e->update_actor_user($db_user) or return $e->die_event;
1300 __PACKAGE__->register_method(
1301 method => "check_user_perms",
1302 api_name => "open-ils.actor.user.perm.check",
1303 notes => <<" NOTES");
1304 Takes a login session, user id, an org id, and an array of perm type strings. For each
1305 perm type, if the user does *not* have the given permission it is added
1306 to a list which is returned from the method. If all permissions
1307 are allowed, an empty list is returned
1308 if the logged in user does not match 'user_id', then the logged in user must
1309 have VIEW_PERMISSION priveleges.
1312 sub check_user_perms {
1313 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1315 my( $staff, $evt ) = $apputils->checkses($login_session);
1316 return $evt if $evt;
1318 if($staff->id ne $user_id) {
1319 if( $evt = $apputils->check_perms(
1320 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1326 for my $perm (@$perm_types) {
1327 if($apputils->check_perms($user_id, $org_id, $perm)) {
1328 push @not_allowed, $perm;
1332 return \@not_allowed
1335 __PACKAGE__->register_method(
1336 method => "check_user_perms2",
1337 api_name => "open-ils.actor.user.perm.check.multi_org",
1339 Checks the permissions on a list of perms and orgs for a user
1340 @param authtoken The login session key
1341 @param user_id The id of the user to check
1342 @param orgs The array of org ids
1343 @param perms The array of permission names
1344 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1345 if the logged in user does not match 'user_id', then the logged in user must
1346 have VIEW_PERMISSION priveleges.
1349 sub check_user_perms2 {
1350 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1352 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1353 $authtoken, $user_id, 'VIEW_PERMISSION' );
1354 return $evt if $evt;
1357 for my $org (@$orgs) {
1358 for my $perm (@$perms) {
1359 if($apputils->check_perms($user_id, $org, $perm)) {
1360 push @not_allowed, [ $org, $perm ];
1365 return \@not_allowed
1369 __PACKAGE__->register_method(
1370 method => 'check_user_perms3',
1371 api_name => 'open-ils.actor.user.perm.highest_org',
1373 Returns the highest org unit id at which a user has a given permission
1374 If the requestor does not match the target user, the requestor must have
1375 'VIEW_PERMISSION' rights at the home org unit of the target user
1376 @param authtoken The login session key
1377 @param userid The id of the user in question
1378 @param perm The permission to check
1379 @return The org unit highest in the org tree within which the user has
1380 the requested permission
1383 sub check_user_perms3 {
1384 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1386 my( $staff, $target, $org, $evt );
1388 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1389 $authtoken, $userid, 'VIEW_PERMISSION' );
1390 return $evt if $evt;
1392 my $tree = $self->get_org_tree();
1393 return _find_highest_perm_org( $perm, $userid, $target->ws_ou, $tree );
1397 sub _find_highest_perm_org {
1398 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1399 my $org = $apputils->find_org($org_tree, $start_org );
1403 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1405 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1411 __PACKAGE__->register_method(
1412 method => 'check_user_perms4',
1413 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1415 Returns the highest org unit id at which a user has a given permission
1416 If the requestor does not match the target user, the requestor must have
1417 'VIEW_PERMISSION' rights at the home org unit of the target user
1418 @param authtoken The login session key
1419 @param userid The id of the user in question
1420 @param perms An array of perm names to check
1421 @return An array of orgId's representing the org unit
1422 highest in the org tree within which the user has the requested permission
1423 The arrah of orgId's has matches the order of the perms array
1426 sub check_user_perms4 {
1427 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1429 my( $staff, $target, $org, $evt );
1431 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1432 $authtoken, $userid, 'VIEW_PERMISSION' );
1433 return $evt if $evt;
1436 return [] unless ref($perms);
1437 my $tree = $self->get_org_tree();
1439 for my $p (@$perms) {
1440 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1448 __PACKAGE__->register_method(
1449 method => "user_fines_summary",
1450 api_name => "open-ils.actor.user.fines.summary",
1451 notes => <<" NOTES");
1452 Returns a short summary of the users total open fines, excluding voided fines
1453 Params are login_session, user_id
1454 Returns a 'mous' object.
1457 sub user_fines_summary {
1458 my( $self, $client, $auth, $user_id ) = @_;
1459 my $e = new_editor(authtoken=>$auth);
1460 return $e->event unless $e->checkauth;
1461 my $user = $e->retrieve_actor_user($user_id)
1462 or return $e->event;
1464 if( $user_id ne $e->requestor->id ) {
1465 return $e->event unless
1466 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1469 # run this inside a transaction to prevent replication delay errors
1470 my $ses = $U->start_db_session();
1471 my $s = $ses->request(
1472 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1473 $U->rollback_db_session($ses);
1480 __PACKAGE__->register_method(
1481 method => "user_transactions",
1482 api_name => "open-ils.actor.user.transactions",
1483 notes => <<" NOTES");
1484 Returns a list of open user transactions (mbts objects);
1485 Params are login_session, user_id
1486 Optional third parameter is the transactions type. defaults to all
1489 __PACKAGE__->register_method(
1490 method => "user_transactions",
1491 api_name => "open-ils.actor.user.transactions.have_charge",
1492 notes => <<" NOTES");
1493 Returns a list of all open user transactions (mbts objects) that have an initial charge
1494 Params are login_session, user_id
1495 Optional third parameter is the transactions type. defaults to all
1498 __PACKAGE__->register_method(
1499 method => "user_transactions",
1500 api_name => "open-ils.actor.user.transactions.have_balance",
1501 notes => <<" NOTES");
1502 Returns a list of all open user transactions (mbts objects) that have a balance
1503 Params are login_session, user_id
1504 Optional third parameter is the transactions type. defaults to all
1507 __PACKAGE__->register_method(
1508 method => "user_transactions",
1509 api_name => "open-ils.actor.user.transactions.fleshed",
1510 notes => <<" NOTES");
1511 Returns an object/hash of transaction, circ, title where transaction = an open
1512 user transactions (mbts objects), circ is the attached circluation, and title
1513 is the title the circ points to
1514 Params are login_session, user_id
1515 Optional third parameter is the transactions type. defaults to all
1518 __PACKAGE__->register_method(
1519 method => "user_transactions",
1520 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1521 notes => <<" NOTES");
1522 Returns an object/hash of transaction, circ, title where transaction = an open
1523 user transactions that has an initial charge (mbts objects), circ is the
1524 attached circluation, and title is the title the circ points to
1525 Params are login_session, user_id
1526 Optional third parameter is the transactions type. defaults to all
1529 __PACKAGE__->register_method(
1530 method => "user_transactions",
1531 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1532 notes => <<" NOTES");
1533 Returns an object/hash of transaction, circ, title where transaction = an open
1534 user transaction that has a balance (mbts objects), circ is the attached
1535 circluation, and title is the title the circ points to
1536 Params are login_session, user_id
1537 Optional third parameter is the transaction type. defaults to all
1540 __PACKAGE__->register_method(
1541 method => "user_transactions",
1542 api_name => "open-ils.actor.user.transactions.count",
1543 notes => <<" NOTES");
1544 Returns an object/hash of transaction, circ, title where transaction = an open
1545 user transactions (mbts objects), circ is the attached circluation, and title
1546 is the title the circ points to
1547 Params are login_session, user_id
1548 Optional third parameter is the transactions type. defaults to all
1551 __PACKAGE__->register_method(
1552 method => "user_transactions",
1553 api_name => "open-ils.actor.user.transactions.have_charge.count",
1554 notes => <<" NOTES");
1555 Returns an object/hash of transaction, circ, title where transaction = an open
1556 user transactions that has an initial charge (mbts objects), circ is the
1557 attached circluation, and title is the title the circ points to
1558 Params are login_session, user_id
1559 Optional third parameter is the transactions type. defaults to all
1562 __PACKAGE__->register_method(
1563 method => "user_transactions",
1564 api_name => "open-ils.actor.user.transactions.have_balance.count",
1565 notes => <<" NOTES");
1566 Returns an object/hash of transaction, circ, title where transaction = an open
1567 user transaction that has a balance (mbts objects), circ is the attached
1568 circluation, and title is the title the circ points to
1569 Params are login_session, user_id
1570 Optional third parameter is the transaction type. defaults to all
1573 __PACKAGE__->register_method(
1574 method => "user_transactions",
1575 api_name => "open-ils.actor.user.transactions.have_balance.total",
1576 notes => <<" NOTES");
1577 Returns an object/hash of transaction, circ, title where transaction = an open
1578 user transaction that has a balance (mbts objects), circ is the attached
1579 circluation, and title is the title the circ points to
1580 Params are login_session, user_id
1581 Optional third parameter is the transaction type. defaults to all
1586 sub user_transactions {
1587 my( $self, $client, $login_session, $user_id, $type ) = @_;
1589 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1590 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1591 return $evt if $evt;
1593 my $api = $self->api_name();
1597 if(defined($type)) { @xact = (xact_type => $type);
1599 } else { @xact = (); }
1602 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1603 ->run($login_session => $user_id => $type);
1605 if($api =~ /have_charge/o) {
1607 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1609 } elsif($api =~ /have_balance/o) {
1611 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1614 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1618 if($api =~ /total/o) {
1620 for my $t (@$trans) {
1621 $total += $t->balance_owed;
1624 $logger->debug("Total balance owed by user $user_id: $total");
1628 if($api =~ /count/o) { return scalar @$trans; }
1629 if($api !~ /fleshed/o) { return $trans; }
1632 for my $t (@$trans) {
1634 if( $t->xact_type ne 'circulation' ) {
1635 push @resp, {transaction => $t};
1639 my $circ = $apputils->simple_scalar_request(
1641 "open-ils.cstore.direct.action.circulation.retrieve",
1646 my $title = $apputils->simple_scalar_request(
1648 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1649 $circ->target_copy );
1653 my $u = OpenILS::Utils::ModsParser->new();
1654 $u->start_mods_batch($title->marc());
1655 my $mods = $u->finish_mods_batch();
1656 $mods->doc_id($title->id) if $mods;
1658 push @resp, {transaction => $t, circ => $circ, record => $mods };
1666 __PACKAGE__->register_method(
1667 method => "user_transaction_retrieve",
1668 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1670 notes => <<" NOTES");
1671 Returns a fleshedtransaction record
1673 __PACKAGE__->register_method(
1674 method => "user_transaction_retrieve",
1675 api_name => "open-ils.actor.user.transaction.retrieve",
1677 notes => <<" NOTES");
1678 Returns a transaction record
1680 sub user_transaction_retrieve {
1681 my( $self, $client, $login_session, $bill_id ) = @_;
1683 # XXX I think I'm deprecated... make sure
1685 my $trans = $apputils->simple_scalar_request(
1687 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1691 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1692 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1693 return $evt if $evt;
1695 my $api = $self->api_name();
1696 if($api !~ /fleshed/o) { return $trans; }
1698 if( $trans->xact_type ne 'circulation' ) {
1699 $logger->debug("Returning non-circ transaction");
1700 return {transaction => $trans};
1703 my $circ = $apputils->simple_scalar_request(
1705 "open-ils..direct.action.circulation.retrieve",
1708 return {transaction => $trans} unless $circ;
1709 $logger->debug("Found the circ transaction");
1711 my $title = $apputils->simple_scalar_request(
1713 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1714 $circ->target_copy );
1716 return {transaction => $trans, circ => $circ } unless $title;
1717 $logger->debug("Found the circ title");
1721 my $u = OpenILS::Utils::ModsParser->new();
1722 $u->start_mods_batch($title->marc());
1723 $mods = $u->finish_mods_batch();
1725 if ($title->id == OILS_PRECAT_RECORD) {
1726 my $copy = $apputils->simple_scalar_request(
1728 "open-ils.cstore.direct.asset.copy.retrieve",
1729 $circ->target_copy );
1731 $mods = new Fieldmapper::metabib::virtual_record;
1732 $mods->doc_id(OILS_PRECAT_RECORD);
1733 $mods->title($copy->dummy_title);
1734 $mods->author($copy->dummy_author);
1738 $logger->debug("MODSized the circ title");
1740 return {transaction => $trans, circ => $circ, record => $mods };
1744 __PACKAGE__->register_method(
1745 method => "hold_request_count",
1746 api_name => "open-ils.actor.user.hold_requests.count",
1748 notes => <<" NOTES");
1749 Returns hold ready/total counts
1751 sub hold_request_count {
1752 my( $self, $client, $login_session, $userid ) = @_;
1754 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1755 $login_session, $userid, 'VIEW_HOLD' );
1756 return $evt if $evt;
1759 my $holds = $apputils->simple_scalar_request(
1761 "open-ils.cstore.direct.action.hold_request.search.atomic",
1764 fulfillment_time => {"=" => undef },
1765 cancel_time => undef,
1770 for my $h (@$holds) {
1771 next unless $h->capture_time and $h->current_copy;
1773 my $copy = $apputils->simple_scalar_request(
1775 "open-ils.cstore.direct.asset.copy.retrieve",
1779 if ($copy and $copy->status == 8) {
1784 return { total => scalar(@$holds), ready => scalar(@ready) };
1788 __PACKAGE__->register_method(
1789 method => "checkedout_count",
1790 api_name => "open-ils.actor.user.checked_out.count__",
1792 notes => <<" NOTES");
1793 Returns a transaction record
1797 sub checkedout_count {
1798 my( $self, $client, $login_session, $userid ) = @_;
1800 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1801 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1802 return $evt if $evt;
1804 my $circs = $apputils->simple_scalar_request(
1806 "open-ils.cstore.direct.action.circulation.search.atomic",
1807 { usr => $userid, stop_fines => undef }
1808 #{ usr => $userid, checkin_time => {"=" => undef } }
1811 my $parser = DateTime::Format::ISO8601->new;
1814 for my $c (@$circs) {
1815 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1816 my $due = $due_dt->epoch;
1818 if ($due < DateTime->today->epoch) {
1823 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1827 __PACKAGE__->register_method(
1828 method => "checked_out",
1829 api_name => "open-ils.actor.user.checked_out",
1832 Returns a structure of circulations objects sorted by
1833 out, overdue, lost, claims_returned, long_overdue.
1834 A list of IDs are returned of each type.
1835 lost, long_overdue, and claims_returned circ will not
1836 be "finished" (there is an outstanding balance or some
1837 other pending action on the circ).
1839 The .count method also includes a 'total' field which
1840 sums all "open" circs
1844 __PACKAGE__->register_method(
1845 method => "checked_out",
1846 api_name => "open-ils.actor.user.checked_out.count",
1848 signature => q/@see open-ils.actor.user.checked_out/
1852 my( $self, $conn, $auth, $userid ) = @_;
1854 my $e = new_editor(authtoken=>$auth);
1855 return $e->event unless $e->checkauth;
1857 if( $userid ne $e->requestor->id ) {
1858 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
1861 my $count = $self->api_name =~ /count/;
1862 return _checked_out( $count, $e, $userid );
1866 my( $iscount, $e, $userid ) = @_;
1869 my $meth = 'open-ils.storage.actor.user.checked_out';
1870 $meth = "$meth.count" if $iscount;
1871 return $U->storagereq($meth, $userid);
1873 # XXX Old code - moved to storage
1874 #------------------------------------------------------------------------------
1875 #------------------------------------------------------------------------------
1876 my $circs = $e->search_action_circulation(
1877 { usr => $userid, checkin_time => undef });
1879 my $parser = DateTime::Format::ISO8601->new;
1881 # split the circs up into overdue and not-overdue circs
1883 for my $c (@$circs) {
1884 if( $c->due_date ) {
1885 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1886 my $due = $due_dt->epoch;
1887 if ($due < DateTime->today->epoch) {
1897 my( @open, @od, @lost, @cr, @lo );
1899 while (my $c = shift(@out)) {
1900 push( @open, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1901 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1902 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1903 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1906 while (my $c = shift(@overdue)) {
1907 push( @od, $c->id ) if (!$c->stop_fines || $c->stop_fines eq 'MAXFINES' || $c->stop_fines eq 'RENEW');
1908 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1909 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1910 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1915 total => @open + @od + @lost + @cr + @lo,
1916 out => scalar(@open),
1917 overdue => scalar(@od),
1918 lost => scalar(@lost),
1919 claims_returned => scalar(@cr),
1920 long_overdue => scalar(@lo)
1928 claims_returned => \@cr,
1929 long_overdue => \@lo
1934 sub _checked_out_WHAT {
1935 my( $iscount, $e, $userid ) = @_;
1937 my $circs = $e->search_action_circulation(
1938 { usr => $userid, stop_fines => undef });
1940 my $mcircs = $e->search_action_circulation(
1943 checkin_time => undef,
1944 xact_finish => undef,
1948 push( @$circs, @$mcircs );
1950 my $parser = DateTime::Format::ISO8601->new;
1952 # split the circs up into overdue and not-overdue circs
1954 for my $c (@$circs) {
1955 if( $c->due_date ) {
1956 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1957 my $due = $due_dt->epoch;
1958 if ($due < DateTime->today->epoch) {
1959 push @overdue, $c->id;
1968 # grab all of the lost, claims-returned, and longoverdue circs
1969 #my $open = $e->search_action_circulation(
1970 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1973 # these items have stop_fines, but no xact_finish, so money
1974 # is owed on them and they have not been checked in
1975 my $open = $e->search_action_circulation(
1978 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1979 xact_finish => undef,
1980 checkin_time => undef,
1985 my( @lost, @cr, @lo );
1986 for my $c (@$open) {
1987 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1988 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1989 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1995 total => @$circs + @lost + @cr + @lo,
1996 out => scalar(@out),
1997 overdue => scalar(@overdue),
1998 lost => scalar(@lost),
1999 claims_returned => scalar(@cr),
2000 long_overdue => scalar(@lo)
2006 overdue => \@overdue,
2008 claims_returned => \@cr,
2009 long_overdue => \@lo
2015 __PACKAGE__->register_method(
2016 method => "checked_in_with_fines",
2017 api_name => "open-ils.actor.user.checked_in_with_fines",
2019 signature => q/@see open-ils.actor.user.checked_out/
2021 sub checked_in_with_fines {
2022 my( $self, $conn, $auth, $userid ) = @_;
2024 my $e = new_editor(authtoken=>$auth);
2025 return $e->event unless $e->checkauth;
2027 if( $userid ne $e->requestor->id ) {
2028 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2031 # money is owed on these items and they are checked in
2032 my $open = $e->search_action_circulation(
2035 xact_finish => undef,
2036 checkin_time => { "!=" => undef },
2041 my( @lost, @cr, @lo );
2042 for my $c (@$open) {
2043 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2044 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2045 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2050 claims_returned => \@cr,
2051 long_overdue => \@lo
2063 __PACKAGE__->register_method(
2064 method => "user_transaction_history",
2065 api_name => "open-ils.actor.user.transactions.history",
2067 notes => <<" NOTES");
2068 Returns a list of billable transaction ids for a user, optionally by type
2070 __PACKAGE__->register_method(
2071 method => "user_transaction_history",
2072 api_name => "open-ils.actor.user.transactions.history.have_charge",
2074 notes => <<" NOTES");
2075 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2077 __PACKAGE__->register_method(
2078 method => "user_transaction_history",
2079 api_name => "open-ils.actor.user.transactions.history.have_balance",
2081 notes => <<" NOTES");
2082 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2084 __PACKAGE__->register_method(
2085 method => "user_transaction_history",
2086 api_name => "open-ils.actor.user.transactions.history.still_open",
2088 notes => <<" NOTES");
2089 Returns a list of billable transaction ids for a user that are not finished
2091 __PACKAGE__->register_method(
2092 method => "user_transaction_history",
2093 api_name => "open-ils.actor.user.transactions.history.have_bill",
2095 notes => <<" NOTES");
2096 Returns a list of billable transaction ids for a user that has billings
2102 sub _user_transaction_history {
2103 my( $self, $client, $login_session, $user_id, $type ) = @_;
2105 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
2106 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
2107 return $evt if $evt;
2109 my $api = $self->api_name();
2114 @xact = (xact_type => $type) if(defined($type));
2115 @balance = (balance_owed => { "!=" => 0}) if($api =~ /have_balance/);
2116 @charge = (last_billing_ts => { "<>" => undef }) if $api =~ /have_charge/;
2118 $logger->debug("searching for transaction history: @xact : @balance, @charge");
2120 my $trans = $apputils->simple_scalar_request(
2122 "open-ils.cstore.direct.money.billable_transaction_summary.search.atomic",
2123 { usr => $user_id, @xact, @charge, @balance }, { order_by => { mbts => 'xact_start DESC' } });
2125 return [ map { $_->id } @$trans ];
2129 =head SEE APPUTILS.PM
2134 for my $x (@xacts) {
2135 my $s = new Fieldmapper::money::billable_transaction_summary;
2138 $s->xact_start( $x->xact_start );
2139 $s->xact_finish( $x->xact_finish );
2143 for my $b (@{ $x->billings }) {
2144 next if ($U->is_true($b->voided));
2145 $to += ($b->amount * 100);
2146 $lb ||= $b->billing_ts;
2147 if ($b->billing_ts ge $lb) {
2148 $lb = $b->billing_ts;
2149 $s->last_billing_note($b->note);
2150 $s->last_billing_ts($b->billing_ts);
2151 $s->last_billing_type($b->billing_type);
2155 $s->total_owed( sprintf('%0.2f', $to / 100 ) );
2159 for my $p (@{ $x->payments }) {
2160 next if ($U->is_true($p->voided));
2161 $tp += ($p->amount * 100);
2162 $lp ||= $p->payment_ts;
2163 if ($p->payment_ts ge $lp) {
2164 $lp = $p->payment_ts;
2165 $s->last_payment_note($p->note);
2166 $s->last_payment_ts($p->payment_ts);
2167 $s->last_payment_type($p->payment_type);
2170 $s->total_paid( sprintf('%0.2f', $tp / 100 ) );
2172 $s->balance_owed( sprintf('%0.2f', ($to - $tp) / 100) );
2174 $s->xact_type( 'grocery' ) if ($x->grocery);
2175 $s->xact_type( 'circulation' ) if ($x->circulation);
2184 sub user_transaction_history {
2185 my( $self, $conn, $auth, $userid, $type ) = @_;
2187 # run inside of a transaction to prevent replication delays
2188 my $e = new_editor(xact=>1, authtoken=>$auth);
2189 return $e->die_event unless $e->checkauth;
2191 if( $e->requestor->id ne $userid ) {
2192 return $e->die_event
2193 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2196 my $api = $self->api_name;
2197 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2199 my @xacts = @{ $e->search_money_billable_transaction(
2200 [ { usr => $userid, @xact_finish },
2202 flesh_fields => { mbt => [ qw/billings payments grocery circulation/ ] },
2203 order_by => { mbt => 'xact_start DESC' },
2211 #my @mbts = _make_mbts( @xacts );
2212 my @mbts = $U->make_mbts( @xacts );
2214 if(defined($type)) {
2215 @mbts = grep { $_->xact_type eq $type } @mbts;
2218 if($api =~ /have_balance/o) {
2219 @mbts = grep { int($_->balance_owed * 100) != 0 } @mbts;
2222 if($api =~ /have_charge/o) {
2223 @mbts = grep { defined($_->last_billing_ts) } @mbts;
2226 if($api =~ /have_bill/o) {
2227 @mbts = grep { int($_->total_owed * 100) != 0 } @mbts;
2235 __PACKAGE__->register_method(
2236 method => "user_perms",
2237 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2239 notes => <<" NOTES");
2240 Returns a list of permissions
2243 my( $self, $client, $authtoken, $user ) = @_;
2245 my( $staff, $evt ) = $apputils->checkses($authtoken);
2246 return $evt if $evt;
2248 $user ||= $staff->id;
2250 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2254 return $apputils->simple_scalar_request(
2256 "open-ils.storage.permission.user_perms.atomic",
2260 __PACKAGE__->register_method(
2261 method => "retrieve_perms",
2262 api_name => "open-ils.actor.permissions.retrieve",
2263 notes => <<" NOTES");
2264 Returns a list of permissions
2266 sub retrieve_perms {
2267 my( $self, $client ) = @_;
2268 return $apputils->simple_scalar_request(
2270 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2271 { id => { '!=' => undef } }
2275 __PACKAGE__->register_method(
2276 method => "retrieve_groups",
2277 api_name => "open-ils.actor.groups.retrieve",
2278 notes => <<" NOTES");
2279 Returns a list of user groupss
2281 sub retrieve_groups {
2282 my( $self, $client ) = @_;
2283 return new_editor()->retrieve_all_permission_grp_tree();
2286 __PACKAGE__->register_method(
2287 method => "retrieve_org_address",
2288 api_name => "open-ils.actor.org_unit.address.retrieve",
2289 notes => <<' NOTES');
2290 Returns an org_unit address by ID
2291 @param An org_address ID
2293 sub retrieve_org_address {
2294 my( $self, $client, $id ) = @_;
2295 return $apputils->simple_scalar_request(
2297 "open-ils.cstore.direct.actor.org_address.retrieve",
2302 __PACKAGE__->register_method(
2303 method => "retrieve_groups_tree",
2304 api_name => "open-ils.actor.groups.tree.retrieve",
2305 notes => <<" NOTES");
2306 Returns a list of user groups
2308 sub retrieve_groups_tree {
2309 my( $self, $client ) = @_;
2310 return new_editor()->search_permission_grp_tree(
2315 flesh_fields => { pgt => ["children"] },
2316 order_by => { pgt => 'name'}
2323 # turns an org list into an org tree
2325 sub build_group_tree {
2327 my( $self, $grplist) = @_;
2329 return $grplist unless (
2330 ref($grplist) and @$grplist > 1 );
2332 my @list = sort { $a->name cmp $b->name } @$grplist;
2335 for my $grp (@list) {
2337 if ($grp and !defined($grp->parent)) {
2341 my ($parent) = grep { $_->id == $grp->parent} @list;
2343 $parent->children([]) unless defined($parent->children);
2344 push( @{$parent->children}, $grp );
2352 __PACKAGE__->register_method(
2353 method => "add_user_to_groups",
2354 api_name => "open-ils.actor.user.set_groups",
2355 notes => <<" NOTES");
2356 Adds a user to one or more permission groups
2359 sub add_user_to_groups {
2360 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2362 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2363 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2364 return $evt if $evt;
2366 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2367 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2368 return $evt if $evt;
2370 $apputils->simplereq(
2372 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2374 for my $group (@$groups) {
2375 my $link = Fieldmapper::permission::usr_grp_map->new;
2377 $link->usr($userid);
2379 my $id = $apputils->simplereq(
2381 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2387 __PACKAGE__->register_method(
2388 method => "get_user_perm_groups",
2389 api_name => "open-ils.actor.user.get_groups",
2390 notes => <<" NOTES");
2391 Retrieve a user's permission groups.
2395 sub get_user_perm_groups {
2396 my( $self, $client, $authtoken, $userid ) = @_;
2398 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2399 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2400 return $evt if $evt;
2402 return $apputils->simplereq(
2404 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2407 __PACKAGE__->register_method(
2408 method => "get_user_work_ous",
2409 api_name => "open-ils.actor.user.get_work_ous",
2410 notes => <<" NOTES");
2411 Retrieve a user's work org units.
2415 sub get_user_work_ous {
2416 my( $self, $client, $authtoken, $userid ) = @_;
2418 my( $requestor, $evt ) = $apputils->checksesperm( $authtoken, 'ASSIGN_WORK_ORG_UNIT' );
2419 return $evt if $evt;
2421 return $apputils->simplereq(
2423 'open-ils.cstore.direct.permission.usr_work_ou_map.search.atomic', { usr => $userid } );
2428 __PACKAGE__->register_method (
2429 method => 'register_workstation',
2430 api_name => 'open-ils.actor.workstation.register.override',
2431 signature => q/@see open-ils.actor.workstation.register/);
2433 __PACKAGE__->register_method (
2434 method => 'register_workstation',
2435 api_name => 'open-ils.actor.workstation.register',
2437 Registers a new workstion in the system
2438 @param authtoken The login session key
2439 @param name The name of the workstation id
2440 @param owner The org unit that owns this workstation
2441 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2442 if the name is already in use.
2445 sub register_workstation {
2446 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2448 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2449 return $e->die_event unless $e->checkauth;
2450 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2451 my $existing = $e->search_actor_workstation({name => $name})->[0];
2455 if( $self->api_name =~ /override/o ) {
2456 # workstation with the given name exists.
2458 if($owner ne $existing->owning_lib) {
2459 # if necessary, update the owning_lib of the workstation
2461 $logger->info("changing owning lib of workstation ".$existing->id.
2462 " from ".$existing->owning_lib." to $owner");
2463 return $e->die_event unless
2464 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2466 $existing->owning_lib($owner);
2467 return $e->die_event unless $e->update_actor_workstation($existing);
2473 "attempt to register an existing workstation. returning existing ID");
2476 return $existing->id;
2479 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2483 my $ws = Fieldmapper::actor::workstation->new;
2484 $ws->owning_lib($owner);
2486 $e->create_actor_workstation($ws) or return $e->die_event;
2488 return $ws->id; # note: editor sets the id on the new object for us
2491 __PACKAGE__->register_method (
2492 method => 'workstation_list',
2493 api_name => 'open-ils.actor.workstation.list',
2495 Returns a list of workstations registered at the given location
2496 @param authtoken The login session key
2497 @param ids A list of org_unit.id's for the workstation owners
2500 sub workstation_list {
2501 my( $self, $conn, $authtoken, @orgs ) = @_;
2503 my $e = new_editor(authtoken=>$authtoken);
2504 return $e->event unless $e->checkauth;
2509 unless $e->allowed('REGISTER_WORKSTATION', $o);
2510 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2521 __PACKAGE__->register_method (
2522 method => 'fetch_patron_note',
2523 api_name => 'open-ils.actor.note.retrieve.all',
2525 Returns a list of notes for a given user
2526 Requestor must have VIEW_USER permission if pub==false and
2527 @param authtoken The login session key
2528 @param args Hash of params including
2529 patronid : the patron's id
2530 pub : true if retrieving only public notes
2534 sub fetch_patron_note {
2535 my( $self, $conn, $authtoken, $args ) = @_;
2536 my $patronid = $$args{patronid};
2538 my($reqr, $evt) = $U->checkses($authtoken);
2539 return $evt if $evt;
2542 ($patron, $evt) = $U->fetch_user($patronid);
2543 return $evt if $evt;
2546 if( $patronid ne $reqr->id ) {
2547 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2548 return $evt if $evt;
2550 return $U->cstorereq(
2551 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2552 { usr => $patronid, pub => 't' } );
2555 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2556 return $evt if $evt;
2558 return $U->cstorereq(
2559 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2562 __PACKAGE__->register_method (
2563 method => 'create_user_note',
2564 api_name => 'open-ils.actor.note.create',
2566 Creates a new note for the given user
2567 @param authtoken The login session key
2568 @param note The note object
2571 sub create_user_note {
2572 my( $self, $conn, $authtoken, $note ) = @_;
2573 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2574 return $e->die_event unless $e->checkauth;
2576 my $user = $e->retrieve_actor_user($note->usr)
2577 or return $e->die_event;
2579 return $e->die_event unless
2580 $e->allowed('UPDATE_USER',$user->home_ou);
2582 $note->creator($e->requestor->id);
2583 $e->create_actor_usr_note($note) or return $e->die_event;
2589 __PACKAGE__->register_method (
2590 method => 'delete_user_note',
2591 api_name => 'open-ils.actor.note.delete',
2593 Deletes a note for the given user
2594 @param authtoken The login session key
2595 @param noteid The note id
2598 sub delete_user_note {
2599 my( $self, $conn, $authtoken, $noteid ) = @_;
2601 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2602 return $e->die_event unless $e->checkauth;
2603 my $note = $e->retrieve_actor_usr_note($noteid)
2604 or return $e->die_event;
2605 my $user = $e->retrieve_actor_user($note->usr)
2606 or return $e->die_event;
2607 return $e->die_event unless
2608 $e->allowed('UPDATE_USER', $user->home_ou);
2610 $e->delete_actor_usr_note($note) or return $e->die_event;
2616 __PACKAGE__->register_method (
2617 method => 'update_user_note',
2618 api_name => 'open-ils.actor.note.update',
2620 @param authtoken The login session key
2621 @param note The note
2625 sub update_user_note {
2626 my( $self, $conn, $auth, $note ) = @_;
2627 my $e = new_editor(authtoken=>$auth, xact=>1);
2628 return $e->event unless $e->checkauth;
2629 my $patron = $e->retrieve_actor_user($note->usr)
2630 or return $e->event;
2631 return $e->event unless
2632 $e->allowed('UPDATE_USER', $patron->home_ou);
2633 $e->update_actor_user_note($note)
2634 or return $e->event;
2642 __PACKAGE__->register_method (
2643 method => 'create_closed_date',
2644 api_name => 'open-ils.actor.org_unit.closed_date.create',
2646 Creates a new closing entry for the given org_unit
2647 @param authtoken The login session key
2648 @param note The closed_date object
2651 sub create_closed_date {
2652 my( $self, $conn, $authtoken, $cd ) = @_;
2654 my( $user, $evt ) = $U->checkses($authtoken);
2655 return $evt if $evt;
2657 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2658 return $evt if $evt;
2660 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2662 my $id = $U->storagereq(
2663 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2664 return $U->DB_UPDATE_FAILED($cd) unless $id;
2669 __PACKAGE__->register_method (
2670 method => 'delete_closed_date',
2671 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2673 Deletes a closing entry for the given org_unit
2674 @param authtoken The login session key
2675 @param noteid The close_date id
2678 sub delete_closed_date {
2679 my( $self, $conn, $authtoken, $cd ) = @_;
2681 my( $user, $evt ) = $U->checkses($authtoken);
2682 return $evt if $evt;
2685 ($cd_obj, $evt) = fetch_closed_date($cd);
2686 return $evt if $evt;
2688 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2689 return $evt if $evt;
2691 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2693 my $stat = $U->storagereq(
2694 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2695 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2700 __PACKAGE__->register_method(
2701 method => 'usrname_exists',
2702 api_name => 'open-ils.actor.username.exists',
2704 Returns 1 if the requested username exists, returns 0 otherwise
2708 sub usrname_exists {
2709 my( $self, $conn, $auth, $usrname ) = @_;
2710 my $e = new_editor(authtoken=>$auth);
2711 return $e->event unless $e->checkauth;
2712 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2713 return $$a[0] if $a and @$a;
2717 __PACKAGE__->register_method(
2718 method => 'barcode_exists',
2719 api_name => 'open-ils.actor.barcode.exists',
2721 Returns 1 if the requested barcode exists, returns 0 otherwise
2725 sub barcode_exists {
2726 my( $self, $conn, $auth, $barcode ) = @_;
2727 my $e = new_editor(authtoken=>$auth);
2728 return $e->event unless $e->checkauth;
2729 my $a = $e->search_actor_card({barcode => $barcode}, {idlist=>1});
2730 return $$a[0] if $a and @$a;
2735 __PACKAGE__->register_method(
2736 method => 'retrieve_net_levels',
2737 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2740 sub retrieve_net_levels {
2741 my( $self, $conn, $auth ) = @_;
2742 my $e = new_editor(authtoken=>$auth);
2743 return $e->event unless $e->checkauth;
2744 return $e->retrieve_all_config_net_access_level();
2748 __PACKAGE__->register_method(
2749 method => 'fetch_org_by_shortname',
2750 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2752 sub fetch_org_by_shortname {
2753 my( $self, $conn, $sname ) = @_;
2754 my $e = new_editor();
2755 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2756 return $e->event unless $org;
2761 __PACKAGE__->register_method(
2762 method => 'session_home_lib',
2763 api_name => 'open-ils.actor.session.home_lib',
2766 sub session_home_lib {
2767 my( $self, $conn, $auth ) = @_;
2768 my $e = new_editor(authtoken=>$auth);
2769 return undef unless $e->checkauth;
2770 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2771 return $org->shortname;
2774 __PACKAGE__->register_method(
2775 method => 'session_safe_token',
2776 api_name => 'open-ils.actor.session.safe_token',
2778 Returns a hashed session ID that is safe for export to the world.
2779 This safe token will expire after 1 hour of non-use.
2780 @param auth Active authentication token
2784 sub session_safe_token {
2785 my( $self, $conn, $auth ) = @_;
2786 my $e = new_editor(authtoken=>$auth);
2787 return undef unless $e->checkauth;
2789 my $safe_token = md5_hex($auth);
2791 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2793 # Add more like the following if needed...
2795 "safe-token-home_lib-shortname-$safe_token",
2796 $e->retrieve_actor_org_unit(
2797 $e->requestor->home_ou
2806 __PACKAGE__->register_method(
2807 method => 'safe_token_home_lib',
2808 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2810 Returns the home library shortname from the session
2811 asscociated with a safe token from generated by
2812 open-ils.actor.session.safe_token.
2813 @param safe_token Active safe token
2817 sub safe_token_home_lib {
2818 my( $self, $conn, $safe_token ) = @_;
2820 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2821 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2826 __PACKAGE__->register_method(
2827 method => 'slim_tree',
2828 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2831 my $tree = new_editor()->search_actor_org_unit(
2833 {"parent_ou" => undef },
2836 flesh_fields => { aou => ['children'] },
2837 order_by => { aou => 'name'},
2838 select => { aou => ["id","shortname", "name"]},
2843 return trim_tree($tree);
2849 return undef unless $tree;
2851 code => $tree->shortname,
2852 name => $tree->name,
2854 if( $tree->children and @{$tree->children} ) {
2855 $htree->{children} = [];
2856 for my $c (@{$tree->children}) {
2857 push( @{$htree->{children}}, trim_tree($c) );
2865 __PACKAGE__->register_method(
2866 method => "update_penalties",
2867 api_name => "open-ils.actor.user.penalties.update");
2868 sub update_penalties {
2869 my( $self, $conn, $auth, $userid ) = @_;
2870 my $e = new_editor(authtoken=>$auth);
2871 return $e->event unless $e->checkauth;
2872 $U->update_patron_penalties(
2874 patronid => $userid,
2881 __PACKAGE__->register_method(
2882 method => "user_retrieve_fleshed_by_id",
2883 api_name => "open-ils.actor.user.fleshed.retrieve",);
2885 sub user_retrieve_fleshed_by_id {
2886 my( $self, $client, $auth, $user_id, $fields ) = @_;
2887 my $e = new_editor(authtoken => $auth);
2888 return $e->event unless $e->checkauth;
2890 if( $e->requestor->id != $user_id ) {
2891 return $e->event unless $e->allowed('VIEW_USER');
2897 "standing_penalties",
2901 "stat_cat_entries" ];
2902 return new_flesh_user($user_id, $fields, $e);
2906 sub new_flesh_user {
2909 my $fields = shift || [];
2910 my $e = shift || new_editor(xact=>1);
2912 my $user = $e->retrieve_actor_user(
2917 "flesh_fields" => { "au" => $fields }
2920 ) or return $e->event;
2923 if( grep { $_ eq 'addresses' } @$fields ) {
2925 $user->addresses([]) unless @{$user->addresses};
2927 if( ref $user->billing_address ) {
2928 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2929 push( @{$user->addresses}, $user->billing_address );
2933 if( ref $user->mailing_address ) {
2934 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2935 push( @{$user->addresses}, $user->mailing_address );
2941 $user->clear_passwd();
2948 __PACKAGE__->register_method(
2949 method => "user_retrieve_parts",
2950 api_name => "open-ils.actor.user.retrieve.parts",);
2952 sub user_retrieve_parts {
2953 my( $self, $client, $auth, $user_id, $fields ) = @_;
2954 my $e = new_editor(authtoken => $auth);
2955 return $e->event unless $e->checkauth;
2956 if( $e->requestor->id != $user_id ) {
2957 return $e->event unless $e->allowed('VIEW_USER');
2960 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
2961 push(@resp, $user->$_()) for(@$fields);
2967 __PACKAGE__->register_method(
2968 method => 'user_opt_in_enabled',
2969 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
2971 @return 1 if user opt-in is globally enabled, 0 otherwise.
2974 sub user_opt_in_enabled {
2975 my($self, $conn) = @_;
2976 my $sc = OpenSRF::Utils::SettingsClient->new;
2977 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
2982 __PACKAGE__->register_method(
2983 method => 'user_opt_in_at_org',
2984 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
2986 @param $auth The auth token
2987 @param user_id The ID of the user to test
2988 @return 1 if the user has opted in at the specified org,
2989 event on error, and 0 otherwise. /);
2990 sub user_opt_in_at_org {
2991 my($self, $conn, $auth, $user_id) = @_;
2993 # see if we even need to enforce the opt-in value
2994 return 1 unless $self->user_opt_in_enabled;
2996 my $e = new_editor(authtoken => $auth);
2997 return $e->event unless $e->checkauth;
2998 my $org_id = $e->requestor->ws_ou;
3000 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3001 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3003 # user is automatically opted-in at the home org
3004 return 1 if $user->home_ou eq $org_id;
3006 my $vals = $e->search_actor_usr_org_unit_opt_in(
3007 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3013 __PACKAGE__->register_method(
3014 method => 'create_user_opt_in_at_org',
3015 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3017 @param $auth The auth token
3018 @param user_id The ID of the user to test
3019 @return The ID of the newly created object, event on error./);
3021 sub create_user_opt_in_at_org {
3022 my($self, $conn, $auth, $user_id) = @_;
3024 my $e = new_editor(authtoken => $auth, xact=>1);
3025 return $e->die_event unless $e->checkauth;
3026 my $org_id = $e->requestor->ws_ou;
3028 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3029 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3031 my $opt_in = Fieldmapper::actor::user_org_unit_opt_in->new;
3033 $opt_in->org_unit($org_id);
3034 $opt_in->usr($user_id);
3035 $opt_in->staff($e->requestor->id);
3036 $opt_in->opt_in_ts('now');
3037 $opt_in->opt_in_ws($e->requestor->wsid);
3039 $opt_in = $e->create_actor_user_org_unit_opt_in($opt_in)
3040 or return $e->die_event;