1 package OpenILS::Application::Actor;
2 use OpenILS::Application;
3 use base qw/OpenILS::Application/;
4 use strict; use warnings;
6 $Data::Dumper::Indent = 0;
9 use Digest::MD5 qw(md5_hex);
11 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::ModsParser;
18 use OpenSRF::Utils::Logger qw/$logger/;
19 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::SettingsClient;
22 use OpenSRF::Utils::Cache;
24 use OpenSRF::Utils::JSON;
26 use DateTime::Format::ISO8601;
27 use OpenILS::Const qw/:const/;
29 use OpenILS::Application::Actor::Container;
30 use OpenILS::Application::Actor::ClosedDates;
31 use OpenILS::Application::Actor::UserGroups;
32 use OpenILS::Application::Actor::Friends;
33 use OpenILS::Application::Actor::Stage;
35 use OpenILS::Utils::CStoreEditor qw/:funcs/;
36 use OpenILS::Utils::Penalty;
39 OpenILS::Application::Actor::Container->initialize();
40 OpenILS::Application::Actor::UserGroups->initialize();
41 OpenILS::Application::Actor::ClosedDates->initialize();
44 my $apputils = "OpenILS::Application::AppUtils";
47 sub _d { warn "Patron:\n" . Dumper(shift()); }
50 my $set_user_settings;
54 #__PACKAGE__->register_method(
55 # method => "allowed_test",
56 # api_name => "open-ils.actor.allowed_test",
59 # my($self, $conn, $auth, $orgid, $permcode) = @_;
60 # my $e = new_editor(authtoken => $auth);
61 # return $e->die_event unless $e->checkauth;
65 # permcode => $permcode,
66 # result => $e->allowed($permcode, $orgid)
70 __PACKAGE__->register_method(
71 method => "update_user_setting",
72 api_name => "open-ils.actor.patron.settings.update",
74 sub update_user_setting {
75 my($self, $conn, $auth, $user_id, $settings) = @_;
76 my $e = new_editor(xact => 1, authtoken => $auth);
77 return $e->die_event unless $e->checkauth;
79 $user_id = $e->requestor->id unless defined $user_id;
81 unless($e->requestor->id == $user_id) {
82 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
83 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
86 for my $name (keys %$settings) {
87 my $val = $$settings{$name};
88 my $set = $e->search_actor_user_setting({usr => $user_id, name => $name})->[0];
91 $val = OpenSRF::Utils::JSON->perl2JSON($val);
94 $e->update_actor_user_setting($set) or return $e->die_event;
96 $set = Fieldmapper::actor::user_setting->new;
100 $e->create_actor_user_setting($set) or return $e->die_event;
103 $e->delete_actor_user_setting($set) or return $e->die_event;
112 __PACKAGE__->register_method(
113 method => "set_ou_settings",
114 api_name => "open-ils.actor.org_unit.settings.update",
117 Updates the value for a given org unit setting. The permission to update
118 an org unit setting is either the UPDATE_ORG_UNIT_SETTING_ALL, or a specific
119 permission specified in the update_perm column of the
120 config.org_unit_setting_type table's row corresponding to the setting being
123 {desc => 'authtoken', type => 'string'},
124 {desc => 'org unit id', type => 'number'},
125 {desc => q/Hash of setting name-value pairs/, type => 'hash'},
127 return => {desc => '1 on success, Event on error'}
131 sub set_ou_settings {
132 my( $self, $client, $auth, $org_id, $settings ) = @_;
134 my $e = new_editor(authtoken => $auth, xact => 1);
135 return $e->die_event unless $e->checkauth;
137 my $all_allowed = $e->allowed("UPDATE_ORG_UNIT_SETTING_ALL", $org_id);
139 for my $name (keys %$settings) {
140 my $val = $$settings{$name};
142 my $type = $e->retrieve_config_org_unit_setting_type([
144 {flesh => 1, flesh_fields => {'coust' => ['update_perm']}}
145 ]) or return $e->die_event;
146 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
148 # If there is no relevant permission, the default assumption will
149 # be, "no, the caller cannot change that value."
150 return $e->die_event unless ($all_allowed ||
151 ($type->update_perm && $e->allowed($type->update_perm->code, $org_id)));
154 $val = OpenSRF::Utils::JSON->perl2JSON($val);
157 $e->update_actor_org_unit_setting($set) or return $e->die_event;
159 $set = Fieldmapper::actor::org_unit_setting->new;
160 $set->org_unit($org_id);
163 $e->create_actor_org_unit_setting($set) or return $e->die_event;
166 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
174 __PACKAGE__->register_method(
175 method => "user_settings",
176 api_name => "open-ils.actor.patron.settings.retrieve",
179 my( $self, $client, $auth, $user_id, $setting ) = @_;
181 my $e = new_editor(authtoken => $auth);
182 return $e->event unless $e->checkauth;
183 $user_id = $e->requestor->id unless defined $user_id;
185 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
186 if($e->requestor->id != $user_id) {
187 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
191 my($e, $user_id, $setting) = @_;
192 my $val = $e->search_actor_user_setting({usr => $user_id, name => $setting})->[0];
193 return '' unless $val; # XXX this should really return undef, but needs testing
194 return OpenSRF::Utils::JSON->JSON2perl($val->value);
198 if(ref $setting eq 'ARRAY') {
200 $settings{$_} = get_setting($e, $user_id, $_) for @$setting;
203 return get_setting($e, $user_id, $setting);
206 my $s = $e->search_actor_user_setting({usr => $user_id});
207 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
213 __PACKAGE__->register_method(
214 method => "ranged_ou_settings",
215 api_name => "open-ils.actor.org_unit_setting.values.ranged.retrieve",
218 Retrieves all org unit settings for the given org_id, up to whatever limit
219 is implied for retrieving OU settings by the authenticated users' permissions./,
221 {desc => 'authtoken', type => 'string'},
222 {desc => 'org unit id', type => 'number'},
224 return => {desc => 'A hashref of "ranged" settings'}
227 sub ranged_ou_settings {
228 my( $self, $client, $auth, $org_id ) = @_;
230 my $e = new_editor(authtoken => $auth);
231 return $e->event unless $e->checkauth;
234 my $org_list = $U->get_org_ancestors($org_id);
235 my $settings = $e->search_actor_org_unit_setting({org_unit => $org_list});
236 $org_list = [ reverse @$org_list ];
238 # start at the context org and capture the setting value
239 # without clobbering settings we've already captured
240 for my $this_org_id (@$org_list) {
242 my @sets = grep { $_->org_unit == $this_org_id } @$settings;
244 for my $set (@sets) {
245 my $type = $e->retrieve_config_org_unit_setting_type([
247 {flesh => 1, flesh_fields => {coust => ['view_perm']}}
250 # If there is no relevant permission, the default assumption will
251 # be, "yes, the caller can have that value."
252 if ($type && $type->view_perm) {
253 next if not $e->allowed($type->view_perm->code, $org_id);
256 $ranged_settings{$set->name} = OpenSRF::Utils::JSON->JSON2perl($set->value)
257 unless defined $ranged_settings{$set->name};
261 return \%ranged_settings;
266 __PACKAGE__->register_method(
267 api_name => 'open-ils.actor.ou_setting.ancestor_default',
268 method => 'ou_ancestor_setting',
270 desc => q/Get an org unit setting value as seen from your org unit. IF AND ONLY IF
271 you provide an authentication token, this method will make sure that the given
272 user has permission to view that setting, if there is a permission associated
275 {desc => 'org unit id', type => 'number'},
276 {desc => 'setting name', type => 'string'},
277 {desc => '(optional) authtoken', type => 'string'},
279 return => {desc => 'A value for the org unit setting, or undef'}
283 # ------------------------------------------------------------------
284 # Attempts to find the org setting value for a given org. if not
285 # found at the requested org, searches up the org tree until it
286 # finds a parent that has the requested setting.
287 # when found, returns { org => $id, value => $value }
288 # otherwise, returns NULL
289 # ------------------------------------------------------------------
290 sub ou_ancestor_setting {
291 my( $self, $client, $orgid, $name, $auth ) = @_;
292 return $U->ou_ancestor_setting($orgid, $name, undef, $auth);
295 __PACKAGE__->register_method(
296 api_name => 'open-ils.actor.ou_setting.ancestor_default.batch',
297 method => 'ou_ancestor_setting_batch',
299 desc => q/Get org unit setting name => value pairs as seen from the specified org unit.
300 IF AND ONLY IF you provide an authentication token, this method will make sure
301 that the given user has permission to view that setting, if there is a
302 permission associated with the setting./,
304 {desc => 'org unit id', type => 'number'},
305 {desc => 'setting name list', type => 'array'},
306 {desc => '(optional) authtoken', type => 'string'},
308 return => {desc => 'A hash with name => value pairs for the org unit settings'}
311 sub ou_ancestor_setting_batch {
312 my( $self, $client, $orgid, $name_list, $auth ) = @_;
314 $values{$_} = $U->ou_ancestor_setting($orgid, $_, undef, $auth) for @$name_list;
322 __PACKAGE__->register_method(
323 method => "update_patron",
324 api_name => "open-ils.actor.patron.update",);
327 my( $self, $client, $user_session, $patron ) = @_;
329 my $session = $apputils->start_db_session();
332 $logger->info("Creating new patron...") if $patron->isnew;
333 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
335 my( $user_obj, $evt ) = $U->checkses($user_session);
338 $evt = check_group_perm($session, $user_obj, $patron);
342 # $new_patron is the patron in progress. $patron is the original patron
343 # passed in with the method. new_patron will change as the components
344 # of patron are added/updated.
348 # unflesh the real items on the patron
349 $patron->card( $patron->card->id ) if(ref($patron->card));
350 $patron->billing_address( $patron->billing_address->id )
351 if(ref($patron->billing_address));
352 $patron->mailing_address( $patron->mailing_address->id )
353 if(ref($patron->mailing_address));
355 # create/update the patron first so we can use his id
356 if($patron->isnew()) {
357 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
359 } else { $new_patron = $patron; }
361 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
364 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
367 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
370 # re-update the patron if anything has happened to him during this process
371 if($new_patron->ischanged()) {
372 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
376 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
379 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
382 $apputils->commit_db_session($session);
384 $evt = apply_invalid_addr_penalty($patron);
387 my $tses = OpenSRF::AppSession->create('open-ils.trigger');
389 $tses->request('open-ils.trigger.event.autocreate', 'au.create', $new_patron, $new_patron->home_ou);
391 $tses->request('open-ils.trigger.event.autocreate', 'au.update', $new_patron, $new_patron->home_ou);
394 return flesh_user($new_patron->id(), new_editor(requestor => $user_obj));
397 sub apply_invalid_addr_penalty {
399 my $e = new_editor(xact => 1);
401 # grab the invalid address penalty if set
402 my $penalties = OpenILS::Utils::Penalty->retrieve_usr_penalties($e, $patron->id, $patron->home_ou);
404 my ($addr_penalty) = grep
405 { $_->standing_penalty->name eq 'INVALID_PATRON_ADDRESS' } @$penalties;
407 # do we enforce invalid address penalty
408 my $enforce = $U->ou_ancestor_setting_value(
409 $patron->home_ou, 'circ.patron_invalid_address_apply_penalty') || 0;
411 my $addrs = $e->search_actor_user_address(
412 {usr => $patron->id, valid => 'f', id => {'>' => 0}}, {idlist => 1});
413 my $addr_count = scalar(@$addrs);
415 if($addr_count == 0 and $addr_penalty) {
417 # regardless of any settings, remove the penalty when the user has no invalid addresses
418 $e->delete_actor_user_standing_penalty($addr_penalty) or return $e->die_event;
421 } elsif($enforce and $addr_count > 0 and !$addr_penalty) {
423 my $ptype = $e->retrieve_config_standing_penalty(29) or return $e->die_event;
424 my $depth = $ptype->org_depth;
425 my $ctx_org = $U->org_unit_ancestor_at_depth($patron->home_ou, $depth) if defined $depth;
426 $ctx_org = $patron->home_ou unless defined $ctx_org;
428 my $penalty = Fieldmapper::actor::user_standing_penalty->new;
429 $penalty->usr($patron->id);
430 $penalty->org_unit($ctx_org);
431 $penalty->standing_penalty(OILS_PENALTY_INVALID_PATRON_ADDRESS);
433 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
447 return new_flesh_user($id, [
450 "standing_penalties",
454 "stat_cat_entries" ], $e );
462 # clone and clear stuff that would break the database
466 my $new_patron = $patron->clone;
468 $new_patron->clear_billing_address();
469 $new_patron->clear_mailing_address();
470 $new_patron->clear_addresses();
471 $new_patron->clear_card();
472 $new_patron->clear_cards();
473 $new_patron->clear_id();
474 $new_patron->clear_isnew();
475 $new_patron->clear_ischanged();
476 $new_patron->clear_isdeleted();
477 $new_patron->clear_stat_cat_entries();
478 $new_patron->clear_permissions();
479 $new_patron->clear_standing_penalties();
489 my $user_obj = shift;
491 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
492 return (undef, $evt) if $evt;
494 my $ex = $session->request(
495 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
497 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
500 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
502 my $id = $session->request(
503 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
504 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
506 $logger->info("Successfully created new user [$id] in DB");
508 return ( $session->request(
509 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
513 sub check_group_perm {
514 my( $session, $requestor, $patron ) = @_;
517 # first let's see if the requestor has
518 # priveleges to update this user in any way
519 if( ! $patron->isnew ) {
520 my $p = $session->request(
521 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
523 # If we are the requestor (trying to update our own account)
524 # and we are not trying to change our profile, we're good
525 if( $p->id == $requestor->id and
526 $p->profile == $patron->profile ) {
531 $evt = group_perm_failed($session, $requestor, $p);
535 # They are allowed to edit this patron.. can they put the
536 # patron into the group requested?
537 $evt = group_perm_failed($session, $requestor, $patron);
543 sub group_perm_failed {
544 my( $session, $requestor, $patron ) = @_;
548 my $grpid = $patron->profile;
552 $logger->debug("user update looking for group perm for group $grpid");
553 $grp = $session->request(
554 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
555 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
557 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
559 $logger->info("user update checking perm $perm on user ".
560 $requestor->id." for update/create on user username=".$patron->usrname);
562 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
570 my( $session, $patron, $user_obj, $noperm) = @_;
572 $logger->info("Updating patron ".$patron->id." in DB");
577 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
578 return (undef, $evt) if $evt;
581 # update the password by itself to avoid the password protection magic
582 if( $patron->passwd ) {
583 my $s = $session->request(
584 'open-ils.storage.direct.actor.user.remote_update',
585 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
586 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
587 $patron->clear_passwd;
590 if(!$patron->ident_type) {
591 $patron->clear_ident_type;
592 $patron->clear_ident_value;
595 $evt = verify_last_xact($session, $patron);
596 return (undef, $evt) if $evt;
598 my $stat = $session->request(
599 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
600 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
605 sub verify_last_xact {
606 my( $session, $patron ) = @_;
607 return undef unless $patron->id and $patron->id > 0;
608 my $p = $session->request(
609 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
610 my $xact = $p->last_xact_id;
611 return undef unless $xact;
612 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
613 return OpenILS::Event->new('XACT_COLLISION')
614 if $xact != $patron->last_xact_id;
619 sub _check_dup_ident {
620 my( $session, $patron ) = @_;
622 return undef unless $patron->ident_value;
625 ident_type => $patron->ident_type,
626 ident_value => $patron->ident_value,
629 $logger->debug("patron update searching for dup ident values: " .
630 $patron->ident_type . ':' . $patron->ident_value);
632 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
634 my $dups = $session->request(
635 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
638 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
645 sub _add_update_addresses {
649 my $new_patron = shift;
653 my $current_id; # id of the address before creation
655 for my $address (@{$patron->addresses()}) {
657 next unless ref $address;
658 $current_id = $address->id();
660 if( $patron->billing_address() and
661 $patron->billing_address() == $current_id ) {
662 $logger->info("setting billing addr to $current_id");
663 $new_patron->billing_address($address->id());
664 $new_patron->ischanged(1);
667 if( $patron->mailing_address() and
668 $patron->mailing_address() == $current_id ) {
669 $new_patron->mailing_address($address->id());
670 $logger->info("setting mailing addr to $current_id");
671 $new_patron->ischanged(1);
675 if($address->isnew()) {
677 $address->usr($new_patron->id());
679 ($address, $evt) = _add_address($session,$address);
680 return (undef, $evt) if $evt;
682 # we need to get the new id
683 if( $patron->billing_address() and
684 $patron->billing_address() == $current_id ) {
685 $new_patron->billing_address($address->id());
686 $logger->info("setting billing addr to $current_id");
687 $new_patron->ischanged(1);
690 if( $patron->mailing_address() and
691 $patron->mailing_address() == $current_id ) {
692 $new_patron->mailing_address($address->id());
693 $logger->info("setting mailing addr to $current_id");
694 $new_patron->ischanged(1);
697 } elsif($address->ischanged() ) {
699 ($address, $evt) = _update_address($session, $address);
700 return (undef, $evt) if $evt;
702 } elsif($address->isdeleted() ) {
704 if( $address->id() == $new_patron->mailing_address() ) {
705 $new_patron->clear_mailing_address();
706 ($new_patron, $evt) = _update_patron($session, $new_patron);
707 return (undef, $evt) if $evt;
710 if( $address->id() == $new_patron->billing_address() ) {
711 $new_patron->clear_billing_address();
712 ($new_patron, $evt) = _update_patron($session, $new_patron);
713 return (undef, $evt) if $evt;
716 $evt = _delete_address($session, $address);
717 return (undef, $evt) if $evt;
721 return ( $new_patron, undef );
725 # adds an address to the db and returns the address with new id
727 my($session, $address) = @_;
728 $address->clear_id();
730 $logger->info("Creating new address at street ".$address->street1);
732 # put the address into the database
733 my $id = $session->request(
734 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
735 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
738 return ($address, undef);
742 sub _update_address {
743 my( $session, $address ) = @_;
745 $logger->info("Updating address ".$address->id." in the DB");
747 my $stat = $session->request(
748 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
750 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
751 return ($address, undef);
756 sub _add_update_cards {
760 my $new_patron = shift;
764 my $virtual_id; #id of the card before creation
765 for my $card (@{$patron->cards()}) {
767 $card->usr($new_patron->id());
769 if(ref($card) and $card->isnew()) {
771 $virtual_id = $card->id();
772 ( $card, $evt ) = _add_card($session,$card);
773 return (undef, $evt) if $evt;
775 #if(ref($patron->card)) { $patron->card($patron->card->id); }
776 if($patron->card() == $virtual_id) {
777 $new_patron->card($card->id());
778 $new_patron->ischanged(1);
781 } elsif( ref($card) and $card->ischanged() ) {
782 $evt = _update_card($session, $card);
783 return (undef, $evt) if $evt;
787 return ( $new_patron, undef );
791 # adds an card to the db and returns the card with new id
793 my( $session, $card ) = @_;
796 $logger->info("Adding new patron card ".$card->barcode);
798 my $id = $session->request(
799 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
800 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
801 $logger->info("Successfully created patron card $id");
804 return ( $card, undef );
808 # returns event on error. returns undef otherwise
810 my( $session, $card ) = @_;
811 $logger->info("Updating patron card ".$card->id);
813 my $stat = $session->request(
814 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
815 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
822 # returns event on error. returns undef otherwise
823 sub _delete_address {
824 my( $session, $address ) = @_;
826 $logger->info("Deleting address ".$address->id." from DB");
828 my $stat = $session->request(
829 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
831 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
837 sub _add_survey_responses {
838 my ($session, $patron, $new_patron) = @_;
840 $logger->info( "Updating survey responses for patron ".$new_patron->id );
842 my $responses = $patron->survey_responses;
846 $_->usr($new_patron->id) for (@$responses);
848 my $evt = $U->simplereq( "open-ils.circ",
849 "open-ils.circ.survey.submit.user_id", $responses );
851 return (undef, $evt) if defined($U->event_code($evt));
855 return ( $new_patron, undef );
859 sub _create_stat_maps {
861 my($session, $user_session, $patron, $new_patron) = @_;
863 my $maps = $patron->stat_cat_entries();
865 for my $map (@$maps) {
867 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
869 if ($map->isdeleted()) {
870 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
872 } elsif ($map->isnew()) {
873 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
878 $map->target_usr($new_patron->id);
881 $logger->info("Updating stat entry with method $method and map $map");
883 my $stat = $session->request($method, $map)->gather(1);
884 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
888 return ($new_patron, undef);
891 sub _create_perm_maps {
893 my($session, $user_session, $patron, $new_patron) = @_;
895 my $maps = $patron->permissions;
897 for my $map (@$maps) {
899 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
900 if ($map->isdeleted()) {
901 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
902 } elsif ($map->isnew()) {
903 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
908 $map->usr($new_patron->id);
910 #warn( "Updating permissions with method $method and session $user_session and map $map" );
911 $logger->info( "Updating permissions with method $method and map $map" );
913 my $stat = $session->request($method, $map)->gather(1);
914 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
918 return ($new_patron, undef);
922 __PACKAGE__->register_method(
923 method => "set_user_work_ous",
924 api_name => "open-ils.actor.user.work_ous.update",
927 sub set_user_work_ous {
933 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
936 my $session = $apputils->start_db_session();
938 for my $map (@$maps) {
940 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
941 if ($map->isdeleted()) {
942 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
943 } elsif ($map->isnew()) {
944 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
948 #warn( "Updating permissions with method $method and session $ses and map $map" );
949 $logger->info( "Updating work_ou map with method $method and map $map" );
951 my $stat = $session->request($method, $map)->gather(1);
952 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
956 $apputils->commit_db_session($session);
958 return scalar(@$maps);
962 __PACKAGE__->register_method(
963 method => "set_user_perms",
964 api_name => "open-ils.actor.user.permissions.update",
973 my $session = $apputils->start_db_session();
975 my( $user_obj, $evt ) = $U->checkses($ses);
978 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
981 $all = 1 if ($U->is_true($user_obj->super_user()));
982 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
984 for my $map (@$maps) {
986 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
987 if ($map->isdeleted()) {
988 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
989 } elsif ($map->isnew()) {
990 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
994 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
995 #warn( "Updating permissions with method $method and session $ses and map $map" );
996 $logger->info( "Updating permissions with method $method and map $map" );
998 my $stat = $session->request($method, $map)->gather(1);
999 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
1003 $apputils->commit_db_session($session);
1005 return scalar(@$maps);
1009 __PACKAGE__->register_method(
1010 method => "user_retrieve_by_barcode",
1012 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
1014 sub user_retrieve_by_barcode {
1015 my($self, $client, $user_session, $barcode) = @_;
1017 $logger->debug("Searching for user with barcode $barcode");
1018 my ($user_obj, $evt) = $apputils->checkses($user_session);
1019 return $evt if $evt;
1021 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
1023 "open-ils.cstore.direct.actor.card.search.atomic",
1024 { barcode => $barcode }
1027 if(!$card || !$card->[0]) {
1028 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
1032 my $user = flesh_user($card->usr(), new_editor(requestor => $user_obj));
1034 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
1035 return $evt if $evt;
1037 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
1044 __PACKAGE__->register_method(
1045 method => "get_user_by_id",
1047 api_name => "open-ils.actor.user.retrieve",);
1049 sub get_user_by_id {
1050 my ($self, $client, $auth, $id) = @_;
1051 my $e = new_editor(authtoken=>$auth);
1052 return $e->event unless $e->checkauth;
1053 my $user = $e->retrieve_actor_user($id)
1054 or return $e->event;
1055 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
1061 __PACKAGE__->register_method(
1062 method => "get_org_types",
1063 api_name => "open-ils.actor.org_types.retrieve",);
1066 return $U->get_org_types();
1071 __PACKAGE__->register_method(
1072 method => "get_user_ident_types",
1073 api_name => "open-ils.actor.user.ident_types.retrieve",
1076 sub get_user_ident_types {
1077 return $ident_types if $ident_types;
1078 return $ident_types =
1079 new_editor()->retrieve_all_config_identification_type();
1085 __PACKAGE__->register_method(
1086 method => "get_org_unit",
1087 api_name => "open-ils.actor.org_unit.retrieve",
1091 my( $self, $client, $user_session, $org_id ) = @_;
1092 my $e = new_editor(authtoken => $user_session);
1094 return $e->event unless $e->checkauth;
1095 $org_id = $e->requestor->ws_ou;
1097 my $o = $e->retrieve_actor_org_unit($org_id)
1098 or return $e->event;
1102 __PACKAGE__->register_method(
1103 method => "search_org_unit",
1104 api_name => "open-ils.actor.org_unit_list.search",
1107 sub search_org_unit {
1109 my( $self, $client, $field, $value ) = @_;
1111 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1113 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1114 { $field => $value } );
1120 # build the org tree
1122 __PACKAGE__->register_method(
1123 method => "get_org_tree",
1124 api_name => "open-ils.actor.org_tree.retrieve",
1126 note => "Returns the entire org tree structure",
1132 return $U->get_org_tree($client->session->session_locale);
1136 __PACKAGE__->register_method(
1137 method => "get_org_descendants",
1138 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1141 # depth is optional. org_unit is the id
1142 sub get_org_descendants {
1143 my( $self, $client, $org_unit, $depth ) = @_;
1145 if(ref $org_unit eq 'ARRAY') {
1148 for my $i (0..scalar(@$org_unit)-1) {
1149 my $list = $U->simple_scalar_request(
1151 "open-ils.storage.actor.org_unit.descendants.atomic",
1152 $org_unit->[$i], $depth->[$i] );
1153 push(@trees, $U->build_org_tree($list));
1158 my $orglist = $apputils->simple_scalar_request(
1160 "open-ils.storage.actor.org_unit.descendants.atomic",
1161 $org_unit, $depth );
1162 return $U->build_org_tree($orglist);
1167 __PACKAGE__->register_method(
1168 method => "get_org_ancestors",
1169 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1172 # depth is optional. org_unit is the id
1173 sub get_org_ancestors {
1174 my( $self, $client, $org_unit, $depth ) = @_;
1175 my $orglist = $apputils->simple_scalar_request(
1177 "open-ils.storage.actor.org_unit.ancestors.atomic",
1178 $org_unit, $depth );
1179 return $U->build_org_tree($orglist);
1183 __PACKAGE__->register_method(
1184 method => "get_standings",
1185 api_name => "open-ils.actor.standings.retrieve"
1190 return $user_standings if $user_standings;
1191 return $user_standings =
1192 $apputils->simple_scalar_request(
1194 "open-ils.cstore.direct.config.standing.search.atomic",
1195 { id => { "!=" => undef } }
1201 __PACKAGE__->register_method(
1202 method => "get_my_org_path",
1203 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1206 sub get_my_org_path {
1207 my( $self, $client, $auth, $org_id ) = @_;
1208 my $e = new_editor(authtoken=>$auth);
1209 return $e->event unless $e->checkauth;
1210 $org_id = $e->requestor->ws_ou unless defined $org_id;
1212 return $apputils->simple_scalar_request(
1214 "open-ils.storage.actor.org_unit.full_path.atomic",
1219 __PACKAGE__->register_method(
1220 method => "patron_adv_search",
1221 api_name => "open-ils.actor.patron.search.advanced" );
1222 sub patron_adv_search {
1223 my( $self, $client, $auth, $search_hash,
1224 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1226 my $e = new_editor(authtoken=>$auth);
1227 return $e->event unless $e->checkauth;
1228 return $e->event unless $e->allowed('VIEW_USER');
1229 return $U->storagereq(
1230 "open-ils.storage.actor.user.crazy_search", $search_hash,
1231 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1235 __PACKAGE__->register_method(
1236 method => "update_passwd",
1238 api_name => "open-ils.actor.user.password.update");
1240 __PACKAGE__->register_method(
1241 method => "update_passwd",
1242 api_name => "open-ils.actor.user.username.update");
1244 __PACKAGE__->register_method(
1245 method => "update_passwd",
1246 api_name => "open-ils.actor.user.email.update");
1249 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1250 my $e = new_editor(xact=>1, authtoken=>$auth);
1251 return $e->die_event unless $e->checkauth;
1253 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1254 or return $e->die_event;
1255 my $api = $self->api_name;
1257 if( $api =~ /password/o ) {
1259 # make sure the original password matches the in-database password
1260 return OpenILS::Event->new('INCORRECT_PASSWORD')
1261 if md5_hex($orig_pw) ne $db_user->passwd;
1262 $db_user->passwd($new_val);
1266 # if we don't clear the password, the user will be updated with
1267 # a hashed version of the hashed version of their password
1268 $db_user->clear_passwd;
1270 if( $api =~ /username/o ) {
1272 # make sure no one else has this username
1273 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1274 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1275 $db_user->usrname($new_val);
1277 } elsif( $api =~ /email/o ) {
1278 $db_user->email($new_val);
1282 $e->update_actor_user($db_user) or return $e->die_event;
1290 __PACKAGE__->register_method(
1291 method => "check_user_perms",
1292 api_name => "open-ils.actor.user.perm.check",
1293 notes => <<" NOTES");
1294 Takes a login session, user id, an org id, and an array of perm type strings. For each
1295 perm type, if the user does *not* have the given permission it is added
1296 to a list which is returned from the method. If all permissions
1297 are allowed, an empty list is returned
1298 if the logged in user does not match 'user_id', then the logged in user must
1299 have VIEW_PERMISSION priveleges.
1302 sub check_user_perms {
1303 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1305 my( $staff, $evt ) = $apputils->checkses($login_session);
1306 return $evt if $evt;
1308 if($staff->id ne $user_id) {
1309 if( $evt = $apputils->check_perms(
1310 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1316 for my $perm (@$perm_types) {
1317 if($apputils->check_perms($user_id, $org_id, $perm)) {
1318 push @not_allowed, $perm;
1322 return \@not_allowed
1325 __PACKAGE__->register_method(
1326 method => "check_user_perms2",
1327 api_name => "open-ils.actor.user.perm.check.multi_org",
1329 Checks the permissions on a list of perms and orgs for a user
1330 @param authtoken The login session key
1331 @param user_id The id of the user to check
1332 @param orgs The array of org ids
1333 @param perms The array of permission names
1334 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1335 if the logged in user does not match 'user_id', then the logged in user must
1336 have VIEW_PERMISSION priveleges.
1339 sub check_user_perms2 {
1340 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1342 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1343 $authtoken, $user_id, 'VIEW_PERMISSION' );
1344 return $evt if $evt;
1347 for my $org (@$orgs) {
1348 for my $perm (@$perms) {
1349 if($apputils->check_perms($user_id, $org, $perm)) {
1350 push @not_allowed, [ $org, $perm ];
1355 return \@not_allowed
1359 __PACKAGE__->register_method(
1360 method => 'check_user_perms3',
1361 api_name => 'open-ils.actor.user.perm.highest_org',
1363 Returns the highest org unit id at which a user has a given permission
1364 If the requestor does not match the target user, the requestor must have
1365 'VIEW_PERMISSION' rights at the home org unit of the target user
1366 @param authtoken The login session key
1367 @param userid The id of the user in question
1368 @param perm The permission to check
1369 @return The org unit highest in the org tree within which the user has
1370 the requested permission
1373 sub check_user_perms3 {
1374 my($self, $client, $authtoken, $user_id, $perm) = @_;
1375 my $e = new_editor(authtoken=>$authtoken);
1376 return $e->event unless $e->checkauth;
1378 my $tree = $U->get_org_tree();
1380 unless($e->requestor->id == $user_id) {
1381 my $user = $e->retrieve_actor_user($user_id)
1382 or return $e->event;
1383 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1384 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1387 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1390 __PACKAGE__->register_method(
1391 method => 'user_has_work_perm_at',
1392 api_name => 'open-ils.actor.user.has_work_perm_at',
1396 Returns a set of org unit IDs which represent the highest orgs in
1397 the org tree where the user has the requested permission. The
1398 purpose of this method is to return the smallest set of org units
1399 which represent the full expanse of the user's ability to perform
1400 the requested action. The user whose perms this method should
1401 check is implied by the authtoken. /,
1403 {desc => 'authtoken', type => 'string'},
1404 {desc => 'permission name', type => 'string'},
1405 {desc => q/user id, optional. If present, check perms for
1406 this user instead of the logged in user/, type => 'number'},
1408 return => {desc => 'An array of org IDs'}
1412 sub user_has_work_perm_at {
1413 my($self, $conn, $auth, $perm, $user_id) = @_;
1414 my $e = new_editor(authtoken=>$auth);
1415 return $e->event unless $e->checkauth;
1416 if(defined $user_id) {
1417 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
1418 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1420 return $U->user_has_work_perm_at($e, $perm, undef, $user_id);
1423 __PACKAGE__->register_method(
1424 method => 'user_has_work_perm_at_batch',
1425 api_name => 'open-ils.actor.user.has_work_perm_at.batch',
1429 sub user_has_work_perm_at_batch {
1430 my($self, $conn, $auth, $perms, $user_id) = @_;
1431 my $e = new_editor(authtoken=>$auth);
1432 return $e->event unless $e->checkauth;
1433 if(defined $user_id) {
1434 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
1435 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1438 $map->{$_} = $U->user_has_work_perm_at($e, $_) for @$perms;
1444 __PACKAGE__->register_method(
1445 method => 'check_user_perms4',
1446 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1448 Returns the highest org unit id at which a user has a given permission
1449 If the requestor does not match the target user, the requestor must have
1450 'VIEW_PERMISSION' rights at the home org unit of the target user
1451 @param authtoken The login session key
1452 @param userid The id of the user in question
1453 @param perms An array of perm names to check
1454 @return An array of orgId's representing the org unit
1455 highest in the org tree within which the user has the requested permission
1456 The arrah of orgId's has matches the order of the perms array
1459 sub check_user_perms4 {
1460 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1462 my( $staff, $target, $org, $evt );
1464 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1465 $authtoken, $userid, 'VIEW_PERMISSION' );
1466 return $evt if $evt;
1469 return [] unless ref($perms);
1470 my $tree = $U->get_org_tree();
1472 for my $p (@$perms) {
1473 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1481 __PACKAGE__->register_method(
1482 method => "user_fines_summary",
1483 api_name => "open-ils.actor.user.fines.summary",
1485 notes => <<" NOTES");
1486 Returns a short summary of the users total open fines, excluding voided fines
1487 Params are login_session, user_id
1488 Returns a 'mous' object.
1491 sub user_fines_summary {
1492 my( $self, $client, $auth, $user_id ) = @_;
1493 my $e = new_editor(authtoken=>$auth);
1494 return $e->event unless $e->checkauth;
1495 my $user = $e->retrieve_actor_user($user_id)
1496 or return $e->event;
1498 if( $user_id ne $e->requestor->id ) {
1499 return $e->event unless
1500 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1503 # run this inside a transaction to prevent replication delay errors
1504 my $ses = $U->start_db_session();
1505 my $s = $ses->request(
1506 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1507 $U->rollback_db_session($ses);
1514 __PACKAGE__->register_method(
1515 method => "user_transactions",
1516 api_name => "open-ils.actor.user.transactions",
1517 notes => <<" NOTES");
1518 Returns a list of open user transactions (mbts objects);
1519 Params are login_session, user_id
1520 Optional third parameter is the transactions type. defaults to all
1523 __PACKAGE__->register_method(
1524 method => "user_transactions",
1525 api_name => "open-ils.actor.user.transactions.have_charge",
1526 notes => <<" NOTES");
1527 Returns a list of all open user transactions (mbts objects) that have an initial charge
1528 Params are login_session, user_id
1529 Optional third parameter is the transactions type. defaults to all
1532 __PACKAGE__->register_method(
1533 method => "user_transactions",
1534 api_name => "open-ils.actor.user.transactions.have_balance",
1536 notes => <<" NOTES");
1537 Returns a list of all open user transactions (mbts objects) that have a balance
1538 Params are login_session, user_id
1539 Optional third parameter is the transactions type. defaults to all
1542 __PACKAGE__->register_method(
1543 method => "user_transactions",
1544 api_name => "open-ils.actor.user.transactions.fleshed",
1545 notes => <<" NOTES");
1546 Returns an object/hash of transaction, circ, title where transaction = an open
1547 user transactions (mbts objects), circ is the attached circluation, and title
1548 is the title the circ points to
1549 Params are login_session, user_id
1550 Optional third parameter is the transactions type. defaults to all
1553 __PACKAGE__->register_method(
1554 method => "user_transactions",
1555 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1556 notes => <<" NOTES");
1557 Returns an object/hash of transaction, circ, title where transaction = an open
1558 user transactions that has an initial charge (mbts objects), circ is the
1559 attached circluation, and title is the title the circ points to
1560 Params are login_session, user_id
1561 Optional third parameter is the transactions type. defaults to all
1564 __PACKAGE__->register_method(
1565 method => "user_transactions",
1566 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1568 notes => <<" NOTES");
1569 Returns an object/hash of transaction, circ, title where transaction = an open
1570 user transaction that has a balance (mbts objects), circ is the attached
1571 circluation, and title is the title the circ points to
1572 Params are login_session, user_id
1573 Optional third parameter is the transaction type. defaults to all
1576 __PACKAGE__->register_method(
1577 method => "user_transactions",
1578 api_name => "open-ils.actor.user.transactions.count",
1579 notes => <<" NOTES");
1580 Returns an object/hash of transaction, circ, title where transaction = an open
1581 user transactions (mbts objects), circ is the attached circluation, and title
1582 is the title the circ points to
1583 Params are login_session, user_id
1584 Optional third parameter is the transactions type. defaults to all
1587 __PACKAGE__->register_method(
1588 method => "user_transactions",
1589 api_name => "open-ils.actor.user.transactions.have_charge.count",
1590 notes => <<" NOTES");
1591 Returns an object/hash of transaction, circ, title where transaction = an open
1592 user transactions that has an initial charge (mbts objects), circ is the
1593 attached circluation, and title is the title the circ points to
1594 Params are login_session, user_id
1595 Optional third parameter is the transactions type. defaults to all
1598 __PACKAGE__->register_method(
1599 method => "user_transactions",
1600 api_name => "open-ils.actor.user.transactions.have_balance.count",
1602 notes => <<" NOTES");
1603 Returns an object/hash of transaction, circ, title where transaction = an open
1604 user transaction that has a balance (mbts objects), circ is the attached
1605 circluation, and title is the title the circ points to
1606 Params are login_session, user_id
1607 Optional third parameter is the transaction type. defaults to all
1610 __PACKAGE__->register_method(
1611 method => "user_transactions",
1612 api_name => "open-ils.actor.user.transactions.have_balance.total",
1614 notes => <<" NOTES");
1615 Returns an object/hash of transaction, circ, title where transaction = an open
1616 user transaction that has a balance (mbts objects), circ is the attached
1617 circluation, and title is the title the circ points to
1618 Params are login_session, user_id
1619 Optional third parameter is the transaction type. defaults to all
1624 sub user_transactions {
1625 my( $self, $client, $login_session, $user_id, $type ) = @_;
1627 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1628 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1629 return $evt if $evt;
1631 my $api = $self->api_name();
1635 if(defined($type)) { @xact = (xact_type => $type);
1637 } else { @xact = (); }
1640 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1641 ->run($login_session => $user_id => $type);
1644 if($api =~ /have_charge/o) {
1646 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1648 } elsif($api =~ /have_balance/o) {
1650 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1653 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1657 if($api =~ /total/o) {
1659 for my $t (@$trans) {
1660 $total += $t->balance_owed;
1663 $logger->debug("Total balance owed by user $user_id: $total");
1667 if($api =~ /count/o) { return scalar @$trans; }
1668 if($api !~ /fleshed/o) { return $trans; }
1671 for my $t (@$trans) {
1673 if( $t->xact_type ne 'circulation' ) {
1674 push @resp, {transaction => $t};
1678 my $circ = $apputils->simple_scalar_request(
1680 "open-ils.cstore.direct.action.circulation.retrieve",
1685 my $title = $apputils->simple_scalar_request(
1687 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1688 $circ->target_copy );
1692 my $u = OpenILS::Utils::ModsParser->new();
1693 $u->start_mods_batch($title->marc());
1694 my $mods = $u->finish_mods_batch();
1695 $mods->doc_id($title->id) if $mods;
1697 push @resp, {transaction => $t, circ => $circ, record => $mods };
1705 __PACKAGE__->register_method(
1706 method => "user_transaction_retrieve",
1707 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1709 notes => <<" NOTES");
1710 Returns a fleshed transaction record
1712 __PACKAGE__->register_method(
1713 method => "user_transaction_retrieve",
1714 api_name => "open-ils.actor.user.transaction.retrieve",
1716 notes => <<" NOTES");
1717 Returns a transaction record
1719 sub user_transaction_retrieve {
1720 my( $self, $client, $login_session, $bill_id ) = @_;
1722 # I think I'm deprecated... make sure. phasefx says, "No, I'll use you :)
1724 my $trans = $apputils->simple_scalar_request(
1726 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1730 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1731 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1732 return $evt if $evt;
1734 my $api = $self->api_name();
1735 if($api !~ /fleshed/o) { return $trans; }
1737 if( $trans->xact_type ne 'circulation' ) {
1738 $logger->debug("Returning non-circ transaction");
1739 return {transaction => $trans};
1742 my $circ = $apputils->simple_scalar_request(
1744 "open-ils.cstore.direct.action.circulation.retrieve",
1747 return {transaction => $trans} unless $circ;
1748 $logger->debug("Found the circ transaction");
1750 my $title = $apputils->simple_scalar_request(
1752 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1753 $circ->target_copy );
1755 return {transaction => $trans, circ => $circ } unless $title;
1756 $logger->debug("Found the circ title");
1759 my $copy = $apputils->simple_scalar_request(
1761 "open-ils.cstore.direct.asset.copy.retrieve",
1762 $circ->target_copy );
1765 my $u = OpenILS::Utils::ModsParser->new();
1766 $u->start_mods_batch($title->marc());
1767 $mods = $u->finish_mods_batch();
1769 if ($title->id == OILS_PRECAT_RECORD) {
1770 $mods = new Fieldmapper::metabib::virtual_record;
1771 $mods->doc_id(OILS_PRECAT_RECORD);
1772 $mods->title($copy->dummy_title);
1773 $mods->author($copy->dummy_author);
1777 $logger->debug("MODSized the circ title");
1779 return {transaction => $trans, circ => $circ, record => $mods, copy => $copy };
1783 __PACKAGE__->register_method(
1784 method => "hold_request_count",
1785 api_name => "open-ils.actor.user.hold_requests.count",
1788 notes => <<" NOTES");
1789 Returns hold ready/total counts
1791 sub hold_request_count {
1792 my( $self, $client, $login_session, $userid ) = @_;
1794 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1795 $login_session, $userid, 'VIEW_HOLD' );
1796 return $evt if $evt;
1799 my $holds = $apputils->simple_scalar_request(
1801 "open-ils.cstore.direct.action.hold_request.search.atomic",
1804 fulfillment_time => {"=" => undef },
1805 cancel_time => undef,
1810 for my $h (@$holds) {
1811 next unless $h->capture_time and $h->current_copy;
1813 my $copy = $apputils->simple_scalar_request(
1815 "open-ils.cstore.direct.asset.copy.retrieve",
1819 if ($copy and $copy->status == 8) {
1824 return { total => scalar(@$holds), ready => scalar(@ready) };
1828 __PACKAGE__->register_method(
1829 method => "checkedout_count",
1830 api_name => "open-ils.actor.user.checked_out.count__",
1832 notes => <<" NOTES");
1833 Returns a transaction record
1837 sub checkedout_count {
1838 my( $self, $client, $login_session, $userid ) = @_;
1840 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1841 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1842 return $evt if $evt;
1844 my $circs = $apputils->simple_scalar_request(
1846 "open-ils.cstore.direct.action.circulation.search.atomic",
1847 { usr => $userid, stop_fines => undef }
1848 #{ usr => $userid, checkin_time => {"=" => undef } }
1851 my $parser = DateTime::Format::ISO8601->new;
1854 for my $c (@$circs) {
1855 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1856 my $due = $due_dt->epoch;
1858 if ($due < DateTime->today->epoch) {
1863 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1867 __PACKAGE__->register_method(
1868 method => "checked_out",
1869 api_name => "open-ils.actor.user.checked_out",
1873 Returns a structure of circulations objects sorted by
1874 out, overdue, lost, claims_returned, long_overdue.
1875 A list of IDs are returned of each type.
1876 lost, long_overdue, and claims_returned circ will not
1877 be "finished" (there is an outstanding balance or some
1878 other pending action on the circ).
1880 The .count method also includes a 'total' field which
1881 sums all "open" circs
1885 __PACKAGE__->register_method(
1886 method => "checked_out",
1887 api_name => "open-ils.actor.user.checked_out.count",
1890 signature => q/@see open-ils.actor.user.checked_out/
1894 my( $self, $conn, $auth, $userid ) = @_;
1896 my $e = new_editor(authtoken=>$auth);
1897 return $e->event unless $e->checkauth;
1899 if( $userid ne $e->requestor->id ) {
1900 my $user = $e->retrieve_actor_user($userid) or return $e->event;
1901 unless($e->allowed('VIEW_CIRCULATIONS', $user->home_ou)) {
1903 # see if there is a friend link allowing circ.view perms
1904 my $allowed = OpenILS::Application::Actor::Friends->friend_perm_allowed(
1905 $e, $userid, $e->requestor->id, 'circ.view');
1906 return $e->event unless $allowed;
1910 my $count = $self->api_name =~ /count/;
1911 return _checked_out( $count, $e, $userid );
1915 my( $iscount, $e, $userid ) = @_;
1916 my $meth = 'open-ils.storage.actor.user.checked_out';
1917 $meth = "$meth.count" if $iscount;
1918 return $U->storagereq($meth, $userid);
1922 sub _checked_out_WHAT {
1923 my( $iscount, $e, $userid ) = @_;
1925 my $circs = $e->search_action_circulation(
1926 { usr => $userid, stop_fines => undef });
1928 my $mcircs = $e->search_action_circulation(
1931 checkin_time => undef,
1932 xact_finish => undef,
1936 push( @$circs, @$mcircs );
1938 my $parser = DateTime::Format::ISO8601->new;
1940 # split the circs up into overdue and not-overdue circs
1942 for my $c (@$circs) {
1943 if( $c->due_date ) {
1944 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1945 my $due = $due_dt->epoch;
1946 if ($due < DateTime->today->epoch) {
1947 push @overdue, $c->id;
1956 # grab all of the lost, claims-returned, and longoverdue circs
1957 #my $open = $e->search_action_circulation(
1958 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1961 # these items have stop_fines, but no xact_finish, so money
1962 # is owed on them and they have not been checked in
1963 my $open = $e->search_action_circulation(
1966 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1967 xact_finish => undef,
1968 checkin_time => undef,
1973 my( @lost, @cr, @lo );
1974 for my $c (@$open) {
1975 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1976 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1977 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1983 total => @$circs + @lost + @cr + @lo,
1984 out => scalar(@out),
1985 overdue => scalar(@overdue),
1986 lost => scalar(@lost),
1987 claims_returned => scalar(@cr),
1988 long_overdue => scalar(@lo)
1994 overdue => \@overdue,
1996 claims_returned => \@cr,
1997 long_overdue => \@lo
2003 __PACKAGE__->register_method(
2004 method => "checked_in_with_fines",
2005 api_name => "open-ils.actor.user.checked_in_with_fines",
2008 signature => q/@see open-ils.actor.user.checked_out/
2010 sub checked_in_with_fines {
2011 my( $self, $conn, $auth, $userid ) = @_;
2013 my $e = new_editor(authtoken=>$auth);
2014 return $e->event unless $e->checkauth;
2016 if( $userid ne $e->requestor->id ) {
2017 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2020 # money is owed on these items and they are checked in
2021 my $open = $e->search_action_circulation(
2024 xact_finish => undef,
2025 checkin_time => { "!=" => undef },
2030 my( @lost, @cr, @lo );
2031 for my $c (@$open) {
2032 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2033 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2034 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2039 claims_returned => \@cr,
2040 long_overdue => \@lo
2052 __PACKAGE__->register_method(
2053 method => "user_transaction_history",
2054 api_name => "open-ils.actor.user.transactions.history",
2056 notes => <<" NOTES");
2057 Returns a list of billable transactions for a user, optionally by type
2059 __PACKAGE__->register_method(
2060 method => "user_transaction_history",
2061 api_name => "open-ils.actor.user.transactions.history.have_charge",
2063 notes => <<" NOTES");
2064 Returns a list of billable transactions for a user that have an initial charge, optionally by type
2066 __PACKAGE__->register_method(
2067 method => "user_transaction_history",
2068 api_name => "open-ils.actor.user.transactions.history.have_balance",
2071 notes => <<" NOTES");
2072 Returns a list of billable transactions for a user that have a balance, optionally by type
2074 __PACKAGE__->register_method(
2075 method => "user_transaction_history",
2076 api_name => "open-ils.actor.user.transactions.history.still_open",
2078 notes => <<" NOTES");
2079 Returns a list of billable transactions for a user that are not finished
2081 __PACKAGE__->register_method(
2082 method => "user_transaction_history",
2083 api_name => "open-ils.actor.user.transactions.history.have_bill",
2086 notes => <<" NOTES");
2087 Returns a list of billable transactions for a user that has billings
2089 __PACKAGE__->register_method(
2090 method => "user_transaction_history",
2091 api_name => "open-ils.actor.user.transactions.history.ids",
2093 notes => <<" NOTES");
2094 Returns a list of billable transaction ids for a user, optionally by type
2096 __PACKAGE__->register_method(
2097 method => "user_transaction_history",
2098 api_name => "open-ils.actor.user.transactions.history.have_charge.ids",
2100 notes => <<" NOTES");
2101 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2103 __PACKAGE__->register_method(
2104 method => "user_transaction_history",
2105 api_name => "open-ils.actor.user.transactions.history.have_balance.ids",
2108 notes => <<" NOTES");
2109 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2111 __PACKAGE__->register_method(
2112 method => "user_transaction_history",
2113 api_name => "open-ils.actor.user.transactions.history.still_open.ids",
2115 notes => <<" NOTES");
2116 Returns a list of billable transaction ids for a user that are not finished
2118 __PACKAGE__->register_method(
2119 method => "user_transaction_history",
2120 api_name => "open-ils.actor.user.transactions.history.have_bill.ids",
2123 notes => <<" NOTES");
2124 Returns a list of billable transaction ids for a user that has billings
2126 __PACKAGE__->register_method(
2127 method => "user_transaction_history",
2128 api_name => "open-ils.actor.user.transactions.history.have_bill_or_payment",
2131 notes => <<" NOTES");
2132 Returns a list of billable transactions for a user that has non-zero-sum billings or at least 1 payment
2134 __PACKAGE__->register_method(
2135 method => "user_transaction_history",
2136 api_name => "open-ils.actor.user.transactions.history.have_bill_or_payment.ids",
2139 notes => <<" NOTES");
2140 Returns a list of billable transaction ids for a user that has non-zero-sum billings or at least 1 payment
2145 sub user_transaction_history {
2146 my( $self, $conn, $auth, $userid, $type ) = @_;
2148 # run inside of a transaction to prevent replication delays
2149 my $e = new_editor(authtoken=>$auth);
2150 return $e->die_event unless $e->checkauth;
2152 if( $e->requestor->id ne $userid ) {
2153 return $e->die_event
2154 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2157 my $api = $self->api_name;
2158 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2160 my $mbts = $e->search_money_billable_transaction_summary(
2162 { usr => $userid, @xact_finish },
2163 { order_by => { mbt => 'xact_start DESC' } }
2167 if(defined($type)) {
2168 @$mbts = grep { $_->xact_type eq $type } @$mbts;
2171 if($api =~ /have_bill_or_payment/o) {
2173 # transactions that have a non-zero sum across all billings or at least 1 payment
2175 int($_->balance_owed * 100) != 0 ||
2176 defined($_->last_payment_ts) } @$mbts;
2178 } elsif( $api =~ /have_balance/o) {
2180 # transactions that have a non-zero overall balance
2181 @$mbts = grep { int($_->balance_owed * 100) != 0 } @$mbts;
2183 } elsif( $api =~ /have_charge/o) {
2185 # transactions that have at least 1 billing, regardless of whether it was voided
2186 @$mbts = grep { defined($_->last_billing_ts) } @$mbts;
2188 } elsif( $api =~ /have_bill/o) {
2190 # transactions that have non-zero sum across all billings. This will exclude
2191 # xacts where all billings have been voided
2192 @$mbts = grep { int($_->total_owed * 100) != 0 } @$mbts;
2195 if ($api =~ /\.ids/) {
2196 return [map {$_->id} @$mbts];
2204 __PACKAGE__->register_method(
2205 method => "user_perms",
2206 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2208 notes => <<" NOTES");
2209 Returns a list of permissions
2212 my( $self, $client, $authtoken, $user ) = @_;
2214 my( $staff, $evt ) = $apputils->checkses($authtoken);
2215 return $evt if $evt;
2217 $user ||= $staff->id;
2219 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2223 return $apputils->simple_scalar_request(
2225 "open-ils.storage.permission.user_perms.atomic",
2229 __PACKAGE__->register_method(
2230 method => "retrieve_perms",
2231 api_name => "open-ils.actor.permissions.retrieve",
2232 notes => <<" NOTES");
2233 Returns a list of permissions
2235 sub retrieve_perms {
2236 my( $self, $client ) = @_;
2237 return $apputils->simple_scalar_request(
2239 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2240 { id => { '!=' => undef } }
2244 __PACKAGE__->register_method(
2245 method => "retrieve_groups",
2246 api_name => "open-ils.actor.groups.retrieve",
2247 notes => <<" NOTES");
2248 Returns a list of user groupss
2250 sub retrieve_groups {
2251 my( $self, $client ) = @_;
2252 return new_editor()->retrieve_all_permission_grp_tree();
2255 __PACKAGE__->register_method(
2256 method => "retrieve_org_address",
2257 api_name => "open-ils.actor.org_unit.address.retrieve",
2258 notes => <<' NOTES');
2259 Returns an org_unit address by ID
2260 @param An org_address ID
2262 sub retrieve_org_address {
2263 my( $self, $client, $id ) = @_;
2264 return $apputils->simple_scalar_request(
2266 "open-ils.cstore.direct.actor.org_address.retrieve",
2271 __PACKAGE__->register_method(
2272 method => "retrieve_groups_tree",
2273 api_name => "open-ils.actor.groups.tree.retrieve",
2274 notes => <<" NOTES");
2275 Returns a list of user groups
2277 sub retrieve_groups_tree {
2278 my( $self, $client ) = @_;
2279 return new_editor()->search_permission_grp_tree(
2284 flesh_fields => { pgt => ["children"] },
2285 order_by => { pgt => 'name'}
2292 __PACKAGE__->register_method(
2293 method => "add_user_to_groups",
2294 api_name => "open-ils.actor.user.set_groups",
2295 notes => <<" NOTES");
2296 Adds a user to one or more permission groups
2299 sub add_user_to_groups {
2300 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2302 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2303 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2304 return $evt if $evt;
2306 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2307 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2308 return $evt if $evt;
2310 $apputils->simplereq(
2312 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2314 for my $group (@$groups) {
2315 my $link = Fieldmapper::permission::usr_grp_map->new;
2317 $link->usr($userid);
2319 my $id = $apputils->simplereq(
2321 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2327 __PACKAGE__->register_method(
2328 method => "get_user_perm_groups",
2329 api_name => "open-ils.actor.user.get_groups",
2330 notes => <<" NOTES");
2331 Retrieve a user's permission groups.
2335 sub get_user_perm_groups {
2336 my( $self, $client, $authtoken, $userid ) = @_;
2338 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2339 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2340 return $evt if $evt;
2342 return $apputils->simplereq(
2344 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2348 __PACKAGE__->register_method(
2349 method => "get_user_work_ous",
2350 api_name => "open-ils.actor.user.get_work_ous",
2351 notes => <<" NOTES");
2352 Retrieve a user's work org units.
2354 __PACKAGE__->register_method(
2355 method => "get_user_work_ous",
2356 api_name => "open-ils.actor.user.get_work_ous.ids",
2357 notes => <<" NOTES");
2358 Retrieve a user's work org units.
2362 sub get_user_work_ous {
2363 my( $self, $client, $auth, $userid ) = @_;
2364 my $e = new_editor(authtoken=>$auth);
2365 return $e->event unless $e->checkauth;
2366 $userid ||= $e->requestor->id;
2368 if($e->requestor->id != $userid) {
2369 my $user = $e->retrieve_actor_user($userid)
2370 or return $e->event;
2371 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2374 return $e->search_permission_usr_work_ou_map({usr => $userid})
2375 unless $self->api_name =~ /.ids$/;
2377 # client just wants a list of org IDs
2378 return $U->get_user_work_ou_ids($e, $userid);
2384 __PACKAGE__->register_method (
2385 method => 'register_workstation',
2386 api_name => 'open-ils.actor.workstation.register.override',
2387 signature => q/@see open-ils.actor.workstation.register/);
2389 __PACKAGE__->register_method (
2390 method => 'register_workstation',
2391 api_name => 'open-ils.actor.workstation.register',
2393 Registers a new workstion in the system
2394 @param authtoken The login session key
2395 @param name The name of the workstation id
2396 @param owner The org unit that owns this workstation
2397 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2398 if the name is already in use.
2401 sub register_workstation {
2402 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2404 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2405 return $e->die_event unless $e->checkauth;
2406 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2407 my $existing = $e->search_actor_workstation({name => $name})->[0];
2411 if( $self->api_name =~ /override/o ) {
2412 # workstation with the given name exists.
2414 if($owner ne $existing->owning_lib) {
2415 # if necessary, update the owning_lib of the workstation
2417 $logger->info("changing owning lib of workstation ".$existing->id.
2418 " from ".$existing->owning_lib." to $owner");
2419 return $e->die_event unless
2420 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2422 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2424 $existing->owning_lib($owner);
2425 return $e->die_event unless $e->update_actor_workstation($existing);
2431 "attempt to register an existing workstation. returning existing ID");
2434 return $existing->id;
2437 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2441 my $ws = Fieldmapper::actor::workstation->new;
2442 $ws->owning_lib($owner);
2444 $e->create_actor_workstation($ws) or return $e->die_event;
2446 return $ws->id; # note: editor sets the id on the new object for us
2449 __PACKAGE__->register_method (
2450 method => 'workstation_list',
2451 api_name => 'open-ils.actor.workstation.list',
2453 Returns a list of workstations registered at the given location
2454 @param authtoken The login session key
2455 @param ids A list of org_unit.id's for the workstation owners
2458 sub workstation_list {
2459 my( $self, $conn, $authtoken, @orgs ) = @_;
2461 my $e = new_editor(authtoken=>$authtoken);
2462 return $e->event unless $e->checkauth;
2467 unless $e->allowed('REGISTER_WORKSTATION', $o);
2468 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2479 __PACKAGE__->register_method (
2480 method => 'fetch_patron_note',
2481 api_name => 'open-ils.actor.note.retrieve.all',
2484 Returns a list of notes for a given user
2485 Requestor must have VIEW_USER permission if pub==false and
2486 @param authtoken The login session key
2487 @param args Hash of params including
2488 patronid : the patron's id
2489 pub : true if retrieving only public notes
2493 sub fetch_patron_note {
2494 my( $self, $conn, $authtoken, $args ) = @_;
2495 my $patronid = $$args{patronid};
2497 my($reqr, $evt) = $U->checkses($authtoken);
2498 return $evt if $evt;
2501 ($patron, $evt) = $U->fetch_user($patronid);
2502 return $evt if $evt;
2505 if( $patronid ne $reqr->id ) {
2506 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2507 return $evt if $evt;
2509 return $U->cstorereq(
2510 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2511 { usr => $patronid, pub => 't' } );
2514 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2515 return $evt if $evt;
2517 return $U->cstorereq(
2518 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2521 __PACKAGE__->register_method (
2522 method => 'create_user_note',
2523 api_name => 'open-ils.actor.note.create',
2525 Creates a new note for the given user
2526 @param authtoken The login session key
2527 @param note The note object
2530 sub create_user_note {
2531 my( $self, $conn, $authtoken, $note ) = @_;
2532 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2533 return $e->die_event unless $e->checkauth;
2535 my $user = $e->retrieve_actor_user($note->usr)
2536 or return $e->die_event;
2538 return $e->die_event unless
2539 $e->allowed('UPDATE_USER',$user->home_ou);
2541 $note->creator($e->requestor->id);
2542 $e->create_actor_usr_note($note) or return $e->die_event;
2548 __PACKAGE__->register_method (
2549 method => 'delete_user_note',
2550 api_name => 'open-ils.actor.note.delete',
2552 Deletes a note for the given user
2553 @param authtoken The login session key
2554 @param noteid The note id
2557 sub delete_user_note {
2558 my( $self, $conn, $authtoken, $noteid ) = @_;
2560 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2561 return $e->die_event unless $e->checkauth;
2562 my $note = $e->retrieve_actor_usr_note($noteid)
2563 or return $e->die_event;
2564 my $user = $e->retrieve_actor_user($note->usr)
2565 or return $e->die_event;
2566 return $e->die_event unless
2567 $e->allowed('UPDATE_USER', $user->home_ou);
2569 $e->delete_actor_usr_note($note) or return $e->die_event;
2575 __PACKAGE__->register_method (
2576 method => 'update_user_note',
2577 api_name => 'open-ils.actor.note.update',
2579 @param authtoken The login session key
2580 @param note The note
2584 sub update_user_note {
2585 my( $self, $conn, $auth, $note ) = @_;
2586 my $e = new_editor(authtoken=>$auth, xact=>1);
2587 return $e->event unless $e->checkauth;
2588 my $patron = $e->retrieve_actor_user($note->usr)
2589 or return $e->event;
2590 return $e->event unless
2591 $e->allowed('UPDATE_USER', $patron->home_ou);
2592 $e->update_actor_user_note($note)
2593 or return $e->event;
2601 __PACKAGE__->register_method (
2602 method => 'create_closed_date',
2603 api_name => 'open-ils.actor.org_unit.closed_date.create',
2605 Creates a new closing entry for the given org_unit
2606 @param authtoken The login session key
2607 @param note The closed_date object
2610 sub create_closed_date {
2611 my( $self, $conn, $authtoken, $cd ) = @_;
2613 my( $user, $evt ) = $U->checkses($authtoken);
2614 return $evt if $evt;
2616 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2617 return $evt if $evt;
2619 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2621 my $id = $U->storagereq(
2622 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2623 return $U->DB_UPDATE_FAILED($cd) unless $id;
2628 __PACKAGE__->register_method (
2629 method => 'delete_closed_date',
2630 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2632 Deletes a closing entry for the given org_unit
2633 @param authtoken The login session key
2634 @param noteid The close_date id
2637 sub delete_closed_date {
2638 my( $self, $conn, $authtoken, $cd ) = @_;
2640 my( $user, $evt ) = $U->checkses($authtoken);
2641 return $evt if $evt;
2644 ($cd_obj, $evt) = fetch_closed_date($cd);
2645 return $evt if $evt;
2647 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2648 return $evt if $evt;
2650 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2652 my $stat = $U->storagereq(
2653 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2654 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2659 __PACKAGE__->register_method(
2660 method => 'usrname_exists',
2661 api_name => 'open-ils.actor.username.exists',
2663 Returns 1 if the requested username exists, returns 0 otherwise
2667 sub usrname_exists {
2668 my( $self, $conn, $auth, $usrname ) = @_;
2669 my $e = new_editor(authtoken=>$auth);
2670 return $e->event unless $e->checkauth;
2671 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2672 return $$a[0] if $a and @$a;
2676 __PACKAGE__->register_method(
2677 method => 'barcode_exists',
2678 api_name => 'open-ils.actor.barcode.exists',
2681 Returns 1 if the requested barcode exists, returns 0 otherwise
2685 sub barcode_exists {
2686 my( $self, $conn, $auth, $barcode ) = @_;
2687 my $e = new_editor(authtoken=>$auth);
2688 return $e->event unless $e->checkauth;
2689 my $card = $e->search_actor_card({barcode => $barcode});
2695 #return undef unless @$card;
2696 #return $card->[0]->usr;
2700 __PACKAGE__->register_method(
2701 method => 'retrieve_net_levels',
2702 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2705 sub retrieve_net_levels {
2706 my( $self, $conn, $auth ) = @_;
2707 my $e = new_editor(authtoken=>$auth);
2708 return $e->event unless $e->checkauth;
2709 return $e->retrieve_all_config_net_access_level();
2713 __PACKAGE__->register_method(
2714 method => 'fetch_org_by_shortname',
2715 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2717 sub fetch_org_by_shortname {
2718 my( $self, $conn, $sname ) = @_;
2719 my $e = new_editor();
2720 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2721 return $e->event unless $org;
2726 __PACKAGE__->register_method(
2727 method => 'session_home_lib',
2728 api_name => 'open-ils.actor.session.home_lib',
2731 sub session_home_lib {
2732 my( $self, $conn, $auth ) = @_;
2733 my $e = new_editor(authtoken=>$auth);
2734 return undef unless $e->checkauth;
2735 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2736 return $org->shortname;
2739 __PACKAGE__->register_method(
2740 method => 'session_safe_token',
2741 api_name => 'open-ils.actor.session.safe_token',
2743 Returns a hashed session ID that is safe for export to the world.
2744 This safe token will expire after 1 hour of non-use.
2745 @param auth Active authentication token
2749 sub session_safe_token {
2750 my( $self, $conn, $auth ) = @_;
2751 my $e = new_editor(authtoken=>$auth);
2752 return undef unless $e->checkauth;
2754 my $safe_token = md5_hex($auth);
2756 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2758 # Add more like the following if needed...
2760 "safe-token-home_lib-shortname-$safe_token",
2761 $e->retrieve_actor_org_unit(
2762 $e->requestor->home_ou
2771 __PACKAGE__->register_method(
2772 method => 'safe_token_home_lib',
2773 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2775 Returns the home library shortname from the session
2776 asscociated with a safe token from generated by
2777 open-ils.actor.session.safe_token.
2778 @param safe_token Active safe token
2782 sub safe_token_home_lib {
2783 my( $self, $conn, $safe_token ) = @_;
2785 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2786 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2791 __PACKAGE__->register_method(
2792 method => 'slim_tree',
2793 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2796 my $tree = new_editor()->search_actor_org_unit(
2798 {"parent_ou" => undef },
2801 flesh_fields => { aou => ['children'] },
2802 order_by => { aou => 'name'},
2803 select => { aou => ["id","shortname", "name"]},
2808 return trim_tree($tree);
2814 return undef unless $tree;
2816 code => $tree->shortname,
2817 name => $tree->name,
2819 if( $tree->children and @{$tree->children} ) {
2820 $htree->{children} = [];
2821 for my $c (@{$tree->children}) {
2822 push( @{$htree->{children}}, trim_tree($c) );
2830 __PACKAGE__->register_method(
2831 method => "update_penalties",
2832 api_name => "open-ils.actor.user.penalties.update");
2834 sub update_penalties {
2835 my($self, $conn, $auth, $user_id) = @_;
2836 my $e = new_editor(authtoken=>$auth, xact => 1);
2837 return $e->die_event unless $e->checkauth;
2838 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2839 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2840 my $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $e->requestor->ws_ou);
2841 return $evt if $evt;
2847 __PACKAGE__->register_method(
2848 method => "apply_penalty",
2849 api_name => "open-ils.actor.user.penalty.apply");
2852 my($self, $conn, $auth, $penalty) = @_;
2854 my $e = new_editor(authtoken=>$auth, xact => 1);
2855 return $e->die_event unless $e->checkauth;
2857 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2858 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2860 my $ptype = $e->retrieve_config_standing_penalty($penalty->standing_penalty) or return $e->die_event;
2863 (defined $ptype->org_depth) ?
2864 $U->org_unit_ancestor_at_depth($penalty->org_unit, $ptype->org_depth) :
2867 $penalty->org_unit($ctx_org);
2868 $penalty->staff($e->requestor->id);
2869 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
2872 return $penalty->id;
2875 __PACKAGE__->register_method(
2876 method => "remove_penalty",
2877 api_name => "open-ils.actor.user.penalty.remove");
2879 sub remove_penalty {
2880 my($self, $conn, $auth, $penalty) = @_;
2881 my $e = new_editor(authtoken=>$auth, xact => 1);
2882 return $e->die_event unless $e->checkauth;
2883 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2884 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2886 $e->delete_actor_user_standing_penalty($penalty) or return $e->die_event;
2891 __PACKAGE__->register_method(
2892 method => "update_penalty_note",
2893 api_name => "open-ils.actor.user.penalty.note.update");
2895 sub update_penalty_note {
2896 my($self, $conn, $auth, $penalty_ids, $note) = @_;
2897 my $e = new_editor(authtoken=>$auth, xact => 1);
2898 return $e->die_event unless $e->checkauth;
2899 for my $penalty_id (@$penalty_ids) {
2900 my $penalty = $e->search_actor_user_standing_penalty( { id => $penalty_id } )->[0];
2901 if (! $penalty ) { return $e->die_event; }
2902 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2903 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2905 $penalty->note( $note ); $penalty->ischanged( 1 );
2907 $e->update_actor_user_standing_penalty($penalty) or return $e->die_event;
2913 __PACKAGE__->register_method(
2914 method => "ranged_penalty_thresholds",
2915 api_name => "open-ils.actor.grp_penalty_threshold.ranged.retrieve",
2919 sub ranged_penalty_thresholds {
2920 my($self, $conn, $auth, $context_org) = @_;
2921 my $e = new_editor(authtoken=>$auth);
2922 return $e->event unless $e->checkauth;
2923 return $e->event unless $e->allowed('VIEW_GROUP_PENALTY_THRESHOLD', $context_org);
2924 my $list = $e->search_permission_grp_penalty_threshold([
2925 {org_unit => $U->get_org_ancestors($context_org)},
2926 {order_by => {pgpt => 'id'}}
2928 $conn->respond($_) for @$list;
2934 __PACKAGE__->register_method(
2935 method => "user_retrieve_fleshed_by_id",
2937 api_name => "open-ils.actor.user.fleshed.retrieve",);
2939 sub user_retrieve_fleshed_by_id {
2940 my( $self, $client, $auth, $user_id, $fields ) = @_;
2941 my $e = new_editor(authtoken => $auth);
2942 return $e->event unless $e->checkauth;
2944 if( $e->requestor->id != $user_id ) {
2945 return $e->event unless $e->allowed('VIEW_USER');
2951 "standing_penalties",
2955 "stat_cat_entries" ];
2956 return new_flesh_user($user_id, $fields, $e);
2960 sub new_flesh_user {
2963 my $fields = shift || [];
2966 my $fetch_penalties = 0;
2967 if(grep {$_ eq 'standing_penalties'} @$fields) {
2968 $fields = [grep {$_ ne 'standing_penalties'} @$fields];
2969 $fetch_penalties = 1;
2972 my $user = $e->retrieve_actor_user(
2977 "flesh_fields" => { "au" => $fields }
2980 ) or return $e->event;
2983 if( grep { $_ eq 'addresses' } @$fields ) {
2985 $user->addresses([]) unless @{$user->addresses};
2986 # don't expose "replaced" addresses by default
2987 $user->addresses([grep {$_->id >= 0} @{$user->addresses}]);
2989 if( ref $user->billing_address ) {
2990 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2991 push( @{$user->addresses}, $user->billing_address );
2995 if( ref $user->mailing_address ) {
2996 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2997 push( @{$user->addresses}, $user->mailing_address );
3002 if($fetch_penalties) {
3003 # grab the user penalties ranged for this location
3004 $user->standing_penalties(
3005 $e->search_actor_user_standing_penalty([
3008 {stop_date => undef},
3009 {stop_date => {'>' => 'now'}}
3011 org_unit => $U->get_org_ancestors($e->requestor->ws_ou)
3014 flesh_fields => {ausp => ['standing_penalty']}
3021 $user->clear_passwd();
3028 __PACKAGE__->register_method(
3029 method => "user_retrieve_parts",
3030 api_name => "open-ils.actor.user.retrieve.parts",);
3032 sub user_retrieve_parts {
3033 my( $self, $client, $auth, $user_id, $fields ) = @_;
3034 my $e = new_editor(authtoken => $auth);
3035 return $e->event unless $e->checkauth;
3036 if( $e->requestor->id != $user_id ) {
3037 return $e->event unless $e->allowed('VIEW_USER');
3040 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3041 push(@resp, $user->$_()) for(@$fields);
3047 __PACKAGE__->register_method(
3048 method => 'user_opt_in_enabled',
3049 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
3051 @return 1 if user opt-in is globally enabled, 0 otherwise.
3054 sub user_opt_in_enabled {
3055 my($self, $conn) = @_;
3056 my $sc = OpenSRF::Utils::SettingsClient->new;
3057 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
3062 __PACKAGE__->register_method(
3063 method => 'user_opt_in_at_org',
3064 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
3066 @param $auth The auth token
3067 @param user_id The ID of the user to test
3068 @return 1 if the user has opted in at the specified org,
3069 event on error, and 0 otherwise. /);
3070 sub user_opt_in_at_org {
3071 my($self, $conn, $auth, $user_id) = @_;
3073 # see if we even need to enforce the opt-in value
3074 return 1 unless user_opt_in_enabled($self);
3076 my $e = new_editor(authtoken => $auth);
3077 return $e->event unless $e->checkauth;
3078 my $org_id = $e->requestor->ws_ou;
3080 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3081 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3083 # user is automatically opted-in at the home org
3084 return 1 if $user->home_ou eq $org_id;
3086 my $vals = $e->search_actor_usr_org_unit_opt_in(
3087 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3093 __PACKAGE__->register_method(
3094 method => 'create_user_opt_in_at_org',
3095 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3097 @param $auth The auth token
3098 @param user_id The ID of the user to test
3099 @return The ID of the newly created object, event on error./);
3101 sub create_user_opt_in_at_org {
3102 my($self, $conn, $auth, $user_id) = @_;
3104 my $e = new_editor(authtoken => $auth, xact=>1);
3105 return $e->die_event unless $e->checkauth;
3106 my $org_id = $e->requestor->ws_ou;
3108 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3109 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3111 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3113 $opt_in->org_unit($org_id);
3114 $opt_in->usr($user_id);
3115 $opt_in->staff($e->requestor->id);
3116 $opt_in->opt_in_ts('now');
3117 $opt_in->opt_in_ws($e->requestor->wsid);
3119 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3120 or return $e->die_event;
3128 __PACKAGE__->register_method (
3129 method => 'retrieve_org_hours',
3130 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
3132 Returns the hours of operation for a specified org unit
3133 @param authtoken The login session key
3134 @param org_id The org_unit ID
3138 sub retrieve_org_hours {
3139 my($self, $conn, $auth, $org_id) = @_;
3140 my $e = new_editor(authtoken => $auth);
3141 return $e->die_event unless $e->checkauth;
3142 $org_id ||= $e->requestor->ws_ou;
3143 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);
3147 __PACKAGE__->register_method (
3148 method => 'verify_user_password',
3149 api_name => 'open-ils.actor.verify_user_password',
3151 Given a barcode or username and the MD5 encoded password,
3152 returns 1 if the password is correct. Returns 0 otherwise.
3156 sub verify_user_password {
3157 my($self, $conn, $auth, $barcode, $username, $password) = @_;
3158 my $e = new_editor(authtoken => $auth);
3159 return $e->die_event unless $e->checkauth;
3161 my $user_by_barcode;
3162 my $user_by_username;
3164 my $card = $e->search_actor_card([
3165 {barcode => $barcode},
3166 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return 0;
3167 $user_by_barcode = $card->usr;
3168 $user = $user_by_barcode;
3171 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return 0;
3172 $user = $user_by_username;
3174 return 0 if (!$user);
3175 return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3176 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3177 return 1 if $user->passwd eq $password;
3181 __PACKAGE__->register_method (
3182 method => 'retrieve_usr_id_via_barcode_or_usrname',
3183 api_name => "open-ils.actor.user.retrieve_id_by_barcode_or_username",
3185 Given a barcode or username returns the id for the user or
3190 sub retrieve_usr_id_via_barcode_or_usrname {
3191 my($self, $conn, $auth, $barcode, $username) = @_;
3192 my $e = new_editor(authtoken => $auth);
3193 return $e->die_event unless $e->checkauth;
3194 my $id_as_barcode= OpenSRF::Utils::SettingsClient->new->config_value(apps => 'open-ils.actor' => app_settings => 'id_as_barcode');
3196 my $user_by_barcode;
3197 my $user_by_username;
3198 $logger->info("$id_as_barcode is the ID as BARCODE");
3200 my $card = $e->search_actor_card([
3201 {barcode => $barcode},
3202 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0];
3203 if ($id_as_barcode =~ /^t/i) {
3205 $user = $e->retrieve_actor_user($barcode);
3206 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if(!$user);
3208 $user_by_barcode = $card->usr;
3209 $user = $user_by_barcode;
3212 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if(!$card);
3213 $user_by_barcode = $card->usr;
3214 $user = $user_by_barcode;
3219 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return OpenILS::Event->new( 'ACTOR_USR_NOT_FOUND' );
3221 $user = $user_by_username;
3223 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if (!$user);
3224 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3225 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3230 __PACKAGE__->register_method (
3231 method => 'merge_users',
3232 api_name => 'open-ils.actor.user.merge',
3235 Given a list of source users and destination user, transfer all data from the source
3236 to the dest user and delete the source user. All user related data is
3237 transferred, including circulations, holds, bookbags, etc.
3243 my($self, $conn, $auth, $master_id, $user_ids, $options) = @_;
3244 my $e = new_editor(xact => 1, authtoken => $auth);
3245 return $e->die_event unless $e->checkauth;
3247 # disallow the merge if any subordinate accounts are in collections
3248 my $colls = $e->search_money_collections_tracker({usr => $user_ids}, {idlist => 1});
3249 return OpenILS::Event->new('MERGED_USER_IN_COLLECTIONS', payload => $user_ids) if @$colls;
3251 my $master_user = $e->retrieve_actor_user($master_id) or return $e->die_event;
3252 my $del_addrs = ($U->ou_ancestor_setting_value(
3253 $master_user->home_ou, 'circ.user_merge.delete_addresses', $e)) ? 't' : 'f';
3254 my $del_cards = ($U->ou_ancestor_setting_value(
3255 $master_user->home_ou, 'circ.user_merge.delete_cards', $e)) ? 't' : 'f';
3256 my $deactivate_cards = ($U->ou_ancestor_setting_value(
3257 $master_user->home_ou, 'circ.user_merge.deactivate_cards', $e)) ? 't' : 'f';
3259 for my $src_id (@$user_ids) {
3260 my $src_user = $e->retrieve_actor_user($src_id) or return $e->die_event;
3262 return $e->die_event unless $e->allowed('MERGE_USERS', $src_user->home_ou);
3263 if($src_user->home_ou ne $master_user->home_ou) {
3264 return $e->die_event unless $e->allowed('MERGE_USERS', $master_user->home_ou);
3267 return $e->die_event unless
3268 $e->json_query({from => [
3283 __PACKAGE__->register_method (
3284 method => 'approve_user_address',
3285 api_name => 'open-ils.actor.user.pending_address.approve',
3292 sub approve_user_address {
3293 my($self, $conn, $auth, $addr) = @_;
3294 my $e = new_editor(xact => 1, authtoken => $auth);
3295 return $e->die_event unless $e->checkauth;
3297 # if the caller passes an address object, assume they want to
3298 # update it first before approving it
3299 $e->update_actor_user_address($addr) or return $e->die_event;
3301 $addr = $e->retrieve_actor_user_address($addr) or return $e->die_event;
3303 my $user = $e->retrieve_actor_user($addr->usr);
3304 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3305 my $result = $e->json_query({from => ['actor.approve_pending_address', $addr->id]})->[0]
3306 or return $e->die_event;
3308 return [values %$result]->[0];
3312 __PACKAGE__->register_method (
3313 method => 'retrieve_friends',
3314 api_name => 'open-ils.actor.friends.retrieve',
3317 returns { confirmed: [], pending_out: [], pending_in: []}
3318 pending_out are users I'm requesting friendship with
3319 pending_in are users requesting friendship with me
3324 sub retrieve_friends {
3325 my($self, $conn, $auth, $user_id, $options) = @_;
3326 my $e = new_editor(authtoken => $auth);
3327 return $e->event unless $e->checkauth;
3328 $user_id ||= $e->requestor->id;
3330 if($user_id != $e->requestor->id) {
3331 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3332 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3335 return OpenILS::Application::Actor::Friends->retrieve_friends(
3336 $e, $user_id, $options);
3341 __PACKAGE__->register_method (
3342 method => 'apply_friend_perms',
3343 api_name => 'open-ils.actor.friends.perms.apply',
3349 sub apply_friend_perms {
3350 my($self, $conn, $auth, $user_id, $delegate_id, @perms) = @_;
3351 my $e = new_editor(authtoken => $auth, xact => 1);
3352 return $e->event unless $e->checkauth;
3354 if($user_id != $e->requestor->id) {
3355 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3356 return $e->die_event unless $e->allowed('VIEW_USER', $user->home_ou);
3359 for my $perm (@perms) {
3361 OpenILS::Application::Actor::Friends->apply_friend_perm(
3362 $e, $user_id, $delegate_id, $perm);
3363 return $evt if $evt;
3371 __PACKAGE__->register_method (
3372 method => 'update_user_pending_address',
3373 api_name => 'open-ils.actor.user.address.pending.cud'
3376 sub update_user_pending_address {
3377 my($self, $conn, $auth, $addr) = @_;
3378 my $e = new_editor(authtoken => $auth, xact => 1);
3379 return $e->event unless $e->checkauth;
3381 if($addr->usr != $e->requestor->id) {
3382 my $user = $e->retrieve_actor_user($addr->usr) or return $e->die_event;
3383 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3387 $e->create_actor_user_address($addr) or return $e->die_event;
3388 } elsif($addr->isdeleted) {
3389 $e->delete_actor_user_address($addr) or return $e->die_event;
3391 $e->update_actor_user_address($addr) or return $e->die_event;
3399 __PACKAGE__->register_method (
3400 method => 'user_events',
3401 api_name => 'open-ils.actor.user.events.circ',
3404 __PACKAGE__->register_method (
3405 method => 'user_events',
3406 api_name => 'open-ils.actor.user.events.ahr',
3411 my($self, $conn, $auth, $user_id, $filters) = @_;
3412 my $e = new_editor(authtoken => $auth);
3413 return $e->event unless $e->checkauth;
3415 (my $obj_type = $self->api_name) =~ s/.*\.([a-z]+)$/$1/;
3416 my $user_field = 'usr';
3419 $filters->{target} = {
3420 select => { $obj_type => ['id'] },
3422 where => {usr => $user_id}
3425 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3426 if($e->requestor->id != $user_id) {
3427 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3430 my $ses = OpenSRF::AppSession->create('open-ils.trigger');
3431 my $req = $ses->request('open-ils.trigger.events_by_target',
3432 $obj_type, $filters, {atevdef => ['reactor', 'validator']}, 2);
3434 while(my $resp = $req->recv) {
3435 my $val = $resp->content;
3436 my $tgt = $val->target;
3438 if($obj_type eq 'circ') {
3439 $tgt->target_copy($e->retrieve_asset_copy($tgt->target_copy));
3441 } elsif($obj_type eq 'ahr') {
3442 $tgt->current_copy($e->retrieve_asset_copy($tgt->current_copy))
3443 if $tgt->current_copy;
3446 $conn->respond($val) if $val;
3452 __PACKAGE__->register_method (
3453 method => 'copy_events',
3454 api_name => 'open-ils.actor.copy.events.circ',
3457 __PACKAGE__->register_method (
3458 method => 'copy_events',
3459 api_name => 'open-ils.actor.copy.events.ahr',
3464 my($self, $conn, $auth, $copy_id, $filters) = @_;
3465 my $e = new_editor(authtoken => $auth);
3466 return $e->event unless $e->checkauth;
3468 (my $obj_type = $self->api_name) =~ s/.*\.([a-z]+)$/$1/;
3470 my $copy = $e->retrieve_asset_copy($copy_id) or return $e->event;
3472 my $copy_field = 'target_copy';
3473 $copy_field = 'current_copy' if $obj_type eq 'ahr';
3476 $filters->{target} = {
3477 select => { $obj_type => ['id'] },
3479 where => {$copy_field => $copy_id}
3483 my $ses = OpenSRF::AppSession->create('open-ils.trigger');
3484 my $req = $ses->request('open-ils.trigger.events_by_target',
3485 $obj_type, $filters, {atevdef => ['reactor', 'validator']}, 2);
3487 while(my $resp = $req->recv) {
3488 my $val = $resp->content;
3489 my $tgt = $val->target;
3491 my $user = $e->retrieve_actor_user($tgt->usr);
3492 if($e->requestor->id != $user->id) {
3493 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3496 $tgt->$copy_field($copy);
3499 $conn->respond($val) if $val;
3508 __PACKAGE__->register_method (
3509 method => 'update_events',
3510 api_name => 'open-ils.actor.user.event.cancel.batch',
3513 __PACKAGE__->register_method (
3514 method => 'update_events',
3515 api_name => 'open-ils.actor.user.event.reset.batch',
3520 my($self, $conn, $auth, $event_ids) = @_;
3521 my $e = new_editor(xact => 1, authtoken => $auth);
3522 return $e->die_event unless $e->checkauth;
3525 for my $id (@$event_ids) {
3527 # do a little dance to determine what user we are ultimately affecting
3528 my $event = $e->retrieve_action_trigger_event([
3531 flesh_fields => {atev => ['event_def'], atevdef => ['hook']}
3533 ]) or return $e->die_event;
3536 if($event->event_def->hook->core_type eq 'circ') {
3537 $user_id = $e->retrieve_action_circulation($event->target)->usr;
3538 } elsif($event->event_def->hook->core_type eq 'ahr') {
3539 $user_id = $e->retrieve_action_hold_request($event->target)->usr;
3544 my $user = $e->retrieve_actor_user($user_id);
3545 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3547 if($self->api_name =~ /cancel/) {
3548 $event->state('invalid');
3549 } elsif($self->api_name =~ /reset/) {
3550 $event->clear_start_time;
3551 $event->clear_update_time;
3552 $event->state('pending');
3555 $e->update_action_trigger_event($event) or return $e->die_event;
3556 $conn->respond({maximum => scalar(@$event_ids), progress => $x++});
3560 return {complete => 1};
3564 __PACKAGE__->register_method (
3565 method => 'really_delete_user',
3566 api_name => 'open-ils.actor.user.delete',
3568 It anonymizes all personally identifiable information in actor.usr. By calling actor.usr_purge_data()
3569 it also purges related data from other tables, sometimes by transferring it to a designated destination user.
3570 The usrname field (along with first_given_name and family_name) is updated to id '-PURGED-' now().
3571 dest_usr_id is only required when deleting a user that performs staff functions.
3575 sub really_delete_user {
3576 my($self, $conn, $auth, $user_id, $dest_user_id) = @_;
3577 my $e = new_editor(authtoken => $auth, xact => 1);
3578 return $e->die_event unless $e->checkauth;
3579 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3580 return $e->die_event unless $e->allowed('DELETE_USER', $user->home_ou);
3581 my $stat = $e->json_query(
3582 {from => ['actor.usr_delete', $user_id, $dest_user_id]})->[0]
3583 or return $e->die_event;
3590 __PACKAGE__->register_method (
3591 method => 'user_payments',
3592 api_name => 'open-ils.actor.user.payments.retrieve',
3595 Returns all payments for a given user. Default order is newest payments first.
3596 @param auth Authentication token
3597 @param user_id The user ID
3598 @param filters An optional hash of filters, including limit, offset, and order_by definitions
3603 my($self, $conn, $auth, $user_id, $filters) = @_;
3606 my $e = new_editor(authtoken => $auth);
3607 return $e->die_event unless $e->checkauth;
3609 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3610 return $e->event unless $e->allowed('VIEW_USER_TRANSACTIONS', $user->home_ou);
3612 # Find all payments for all transactions for user $user_id
3614 select => {mp => ['id']},
3619 select => {mbt => ['id']},
3621 where => {usr => $user_id}
3625 order_by => [{ # by default, order newest payments first
3627 field => 'payment_ts',
3632 for (qw/order_by limit offset/) {
3633 $query->{$_} = $filters->{$_} if defined $filters->{$_};
3636 my $payment_ids = $e->json_query($query);
3637 $conn->respond($e->retrieve_money_payment($_->{id})) for @$payment_ids;