From: Bill Erickson Date: Fri, 25 Oct 2013 18:24:49 +0000 (-0400) Subject: ff : initial EG perl diffs import X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=17023e07b79a6f3d5cbf03954a7ed8998da5cbb2;p=evergreen%2Fequinox.git ff : initial EG perl diffs import Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm index 9c9efc490d..1a8ff3c110 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm @@ -72,6 +72,286 @@ my $set_ou_settings; #} __PACKAGE__->register_method( + method => 'fetch_web_action_print_template', + api_name => 'open-ils.actor.web_action_print_template.fetch', + signature => q/ + Given a blob of ILL action status information, generate some useful HTML for printing, based on the acting org unit and action. + @param authtoken Login session key + @pararm blob Action status blob + / +); +sub fetch_web_action_print_template { + my( $self, $client, $owner, $focus, $action, $direction ) = @_; + my $e = new_editor(); + my $orgs = $U->get_org_ancestors($owner); + + return $e->search_actor_web_action_print_template([ + { owner => $orgs, + focus => $focus, + -or => [{action => $action},{action => undef}], + -or => [{direction => $direction},{direction => undef}] + }, + { order_by => [ + { class => 'awapt', + field => 'action', + compare => { '=' => undef } + }, + { class => 'awapt', + field => 'direction', + compare => { '=' => undef } + } + ]} + ])->[0]; +} + +sub find_user_lib { + my $lib = shift; + my $e = new_editor(); + + $lib = $e->retrieve_actor_org_unit($lib) if (!ref($lib)); + + while ($lib) { + my $type = $e->retrieve_actor_org_unit_type($lib->ou_type); + return $lib if ($U->is_true($type->can_have_users)); + return undef unless ($lib->parent_ou); + $lib = $e->retrieve_actor_org_unit($lib->parent_ou); + } + + return undef; +} + +__PACKAGE__->register_method( + method => "remote_auth_init", + api_name => "open-ils.actor.remote.authenticate.init", +); +sub remote_auth_init { + my($self, $client, $uname, $uhome) = @_; + + $uhome = find_user_lib($uhome); + return 0 if (!$uhome); + + $uhome = $uhome->id; + + my $e = new_editor(); + my $user = $e->search_actor_user({ + usrname => "$uname:$uhome", + home_ou => $uhome, + # deleted accounts must be re-fetched, updated, and + # un-deleted in open-ils.actor.remote.authenticate.complete + deleted => 'f' + }); + + return -1 unless @$user; # No local user matching the requested criteria, yet + return $U->simplereq( "open-ils.auth", "open-ils.auth.authenticate.init", "$uname:$uhome" ); +} + +__PACKAGE__->register_method( + method => "remote_auth_complete", + api_name => "open-ils.actor.remote.authenticate.complete", +); +sub remote_auth_complete { + my($self, $client, $args) = @_; + + my $uhome = find_user_lib($$args{home}); + return $U->DB_UPDATE_FAILED() if (!$uhome); + + $$args{home} = $uhome->id; + + my $actor = OpenSRF::AppSession->create("open-ils.actor"); + my $ugroup = $actor->request( + "open-ils.actor.ou_setting.ancestor_default", + $$args{home},"ff.remote.user_cache.default_group" + )->gather(1); + + if ($ugroup && ref($ugroup)) { + $ugroup = $ugroup->{'value'}; + } else { + $ugroup = 1; + } + + my $e = new_editor(); + my $user = $e->search_actor_user({ + usrname => "$$args{username}:$$args{home}", + home_ou => $$args{home} + })->[0]; + + my $remote_user; + if (!$user or $U->is_true($user->deleted)) { + + $remote_user = $U->simplereq( + "fulfillment.laicore", + "fulfillment.laicore.lookup_user", + $$args{home}, $$args{username}, $$args{password} + ); + + $remote_user = OpenSRF::Utils::JSON->JSON2perl($remote_user) + if (!ref($remote_user)); # XXX arg.... (what's this now?) + } + + + my $seed_needed = 0; + if ($user) { + if ($U->is_true($user->deleted)) { + my $evt = resurrect_user($user, $remote_user, $ugroup, $args); + return $evt if $evt; + $seed_needed = 1; + } + } else { + + my $u = $remote_user; + + if ($u && !$$u{error}) { # create user ... + $seed_needed = 1; + + $logger->info("FF creating new user for $$args{username}"); + + for my $k (keys %$u) { + delete $$u{$k} if ref($$u{$k}); + } + + my $evt; + my $patron = Fieldmapper::actor::user->new(); + my $card = Fieldmapper::actor::card->new(); + + # how we find them locally + $patron->usrname( "$$args{username}:$$args{home}" ); + $patron->passwd( $$args{password} ); + $patron->profile( $ugroup ); + $patron->home_ou( $$args{home} ); + $patron->ident_type(3); + + # what we can glean from the remote system + $patron->first_given_name( $$u{given_name} || '...' ); + $patron->family_name( $$u{surname} || '...' ); + $patron->suffix( $$u{suffix} ); + $patron->prefix( $$u{prefix} ); + $patron->alias( $$u{initials} ); + + # Set up all of the virtual IDs, isnew, etc. + $patron->isnew(1); + $patron->id(-1); + $patron->card(-1); + + $card->isnew(1); + $card->id(-1); + $card->usr(-1); + $card->org($$args{home}); + $card->barcode($$u{user_barcode} || $$u{user_id} || $$args{username}); + + $patron->cards([$card]); + + my $session = $apputils->start_db_session(); + $logger->info("Creating new remote-proxy patron..."); + + # $new_patron is the patron in progress. $patron is the original patron + # passed in with the method. new_patron will change as the components + # of patron are added/updated. + + my $new_patron; + + # unflesh the real items on the patron + $patron->card( $patron->card->id ) if(ref($patron->card)); + + # create the patron first so we can use his id + my $id = $session->request( "open-ils.storage.direct.actor.user.create", $patron)->gather(1); + return $U->DB_UPDATE_FAILED($patron) unless $id; + + $logger->info("Successfully created new user [$id] in DB"); + + $new_patron = $session->request( "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1); + + ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron); + return $evt if $evt; + + # re-update the patron + ( $new_patron, $evt ) = _update_patron($session, $new_patron, undef, 1); + return $evt if $evt; + + $apputils->commit_db_session($session); + } + } + + $$args{username} = "$$args{username}:$$args{home}"; + + if ($seed_needed) { + # initial call to .init exited early w/ no seed, + # so we need to create one now that we have a user + my $seed = $U->simplereq( + "open-ils.auth", + "open-ils.auth.authenticate.init", + $$args{username} + ); + + $$args{password} = md5_hex($seed . md5_hex($$args{password})); + } + + return $U->simplereq( "open-ils.auth", "open-ils.auth.authenticate.complete", $args ); +} + +# the steps involved in user resurrection are just different +# enough from user creation that blending them into one chain +# of code gets messy. There may some room for combining +# and refactoring here, since there is some duplication. +sub resurrect_user { + my $user = shift; + my $remote_user = shift; + my $ugroup = shift; + my $args = shift; + + $logger->info("Resurrecting deleted user ".$user->id); + + my $e = new_editor(xact => 1); + + my $card = $e->search_actor_card({usr => $user->id})->[0]; + + if (!$card) { + $card = Fieldmapper::actor::card->new(); + $card->usr($user->id); + $card->isnew(1); # for our own tracking + $user->clear_card; + } + + $user->deleted('f'); + $user->usrname("$$args{username}:$$args{home}"); + $user->passwd($$args{password}); + $user->profile($ugroup); + $user->home_ou($$args{home}); + $user->ident_type(3); + + # what we can glean from the remote system + my $u = $remote_user; + $user->first_given_name($$u{given_name} || '...'); + $user->family_name($$u{surname} || '...'); + $user->suffix($$u{suffix}); + $user->prefix($$u{prefix}); + $user->alias($$u{initials}); + $card->org($$args{home}); + $card->barcode($$u{user_barcode} || $$u{user_id} || $$args{username}); + + $e->update_actor_user($user) or return $e->die_event; + + if ($card->isnew) { + # create the new card and update the user + # object to refer to the card + + $e->create_actor_card($card) or return $e->die_event; + + # created a new card, tell the user object about it. + $user->card($card->id); + $e->update_actor_user($user) or return $e->die_event; + + } else { + $e->update_actor_card($card) or return $e->die_event; + } + + $e->commit; + return; +} + + + + +__PACKAGE__->register_method( method => "update_user_setting", api_name => "open-ils.actor.patron.settings.update", ); diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm index fbf140a0ef..322c83f563 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat.pm @@ -125,6 +125,24 @@ sub create_record_xml { return $s; } +__PACKAGE__->register_method( + method => "purge_bibs_by_owner", + api_name => "open-ils.cat.biblio.record.purge_by_owner", + signature => q/ Inserts a new biblio with the given XML / +); + +sub purge_bibs_by_owner { + my( $self, $client, $auth, $owner ) = @_; + + my $e = new_editor(authtoken => $auth); + return $e->die_event unless $e->checkauth; + return $e->die_event unless $e->allowed('UPDATE_MARC', $owner); + + return OpenSRF::AppSession + ->create("open-ils.storage") + ->request("open-ils.storage.biblio.record_entry.purge_by_owner", $owner ) + ->gather(1); +} __PACKAGE__->register_method( diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm index 76f1cb0674..57947b668b 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm @@ -1869,4 +1869,214 @@ sub get_copy_due_date { # {"select":{"acp":["id"],"circ":[{"aggregate":true,"transform":"count","alias":"count","column":"id"}]},"from":{"acp":{"circ":{"field":"target_copy","fkey":"id","type":"left"},"acn"{"field":"id","fkey":"call_number"}}},"where":{"+acn":{"record":200057}} +__PACKAGE__->register_method( + method => "item_transaction_disposition", + api_name => "open-ils.circ.item.transaction.disposition", + signature => { + desc => q/Given an item barcode, determines the disposition of the + copy with regard to open transactions. The goal is to report + on where the copy is going (if en route to or from a hold or + transit) or whether the copy is circulating. Since it's + possible for more than one copy with the provided barcode may + have some relationship to the context org unit, some data is + returned as arrays, while other data is returned as a single + object. + + Lender transactions each are limited to one occurrence in total, + because they refer to a specific copy, which lives within ctx_ou. + All other actions may refer to multiple copies and thus have + multiple transactions. + + Lender transit is the transit back home of the loaned copy + Borrower transits are all transits to elsewhere by copies + owned elsewhere. + /, + params => [ + {desc => 'Authentication token', type => 'string'}, + {desc => 'Context Org Unit ID', type => 'number'}, + {desc => 'Copy Barcodde', type => 'string'}, + ], + return => {desc => q/ + Array of copies, sorted by locally owned copy first, followed + by copies owned by others. Each field in the response, minus + the 'copy' field, is optionally. + { copy : + circ : + hold : + transit : + } + /} + } +); + +sub item_transaction_disposition { + my ($self, $client, $auth, $ctx_ou, $barcode) = @_; + + my $e = new_editor(authtoken => $auth); + return $e->event unless $e->checkauth; + return $e->event unless $e->allowed('VIEW_CIRCULATIONS'); # catchall + + # context ou may be a parent or a child of the various transaction + # and item owning lib org units. + my $org_list = $U->get_org_full_path($ctx_ou); + + my $local_copy = $e->search_asset_copy({ + deleted => 'f', + barcode => $barcode, + circ_lib => $org_list + })->[0]; + + my $remote_copies = $e->search_asset_copy({ + deleted => 'f', + barcode => $barcode, + circ_lib => {'not in' => $org_list} + }); + + my @resp; + + push(@resp, + collect_copy_transactions( + $e, $local_copy->id, $ctx_ou, $org_list, 1) + ) if $local_copy; + + push(@resp, + collect_copy_transactions( + $e, $_->id, $ctx_ou, $org_list) + ) for @$remote_copies; + + return \@resp; +} + +sub collect_copy_transactions { + my ($e, $copy_id, $ctx_ou, $org_list, $local) = @_; + my $next_action = ''; + + my $transit_flesh = { + flesh => 4, + flesh_fields => { + atc => ['source', 'dest', 'hold_transit_copy'], + ahtc => ['hold'], + ahr => ['usr'], + au => ['card'], + aou => ['ill_address'] + } + }; + + my $circ_flesh = { + flesh => 2, + flesh_fields => { + circ => ['usr'], + au => ['card'] + } + }; + + my $hold_flesh = { + flesh => 3, + flesh_fields => { + ahr => ['transit', 'usr', 'cancel_cause'], + au => ['card'], + ahtc => ['source', 'dest'] + } + }; + + my %resp = ( + copy => $e->retrieve_asset_copy([ + $copy_id, { + flesh => 3, + flesh_fields => { + acp => ['call_number', 'status'], + acn => ['record'], + # flesh simple_record for now as a hack to display title/author + bre => ['simple_record'] + } + } + ]) + ); + + $resp{copy}->call_number->record->clear_marc; + + my $hold = $e->search_action_hold_request([ + { fulfillment_time => undef, + cancel_time => undef, + frozen => 'f', + current_copy => $copy_id + }, $hold_flesh + ])->[0]; + + if ($hold) { + if ($local) { + $next_action = 'ill-home-capture' unless $hold->capture_time; + $resp{can_retarget_hold} = 1; + + } else { + # for non-local copies, only the borrower can cancel + # or retarget the hold + if (grep {$hold->request_lib == $_} @$org_list) { + $resp{can_cancel_hold} = 1; + $resp{can_retarget_hold} = 1; + } + + if ($hold->pickup_lib == $ctx_ou) { + + # hold is en route to here, maybe there is work for us to do + + if ($hold->shelf_time) { + $next_action = 'ill-foreign-checkout'; + } elsif ($hold->capture_time) { + $next_action = 'ill-foreign-receive'; + } + } + } + + $resp{hold} = $hold; + } + + # non-local copies must be circulting "here" to be relevant + my %circ_filter = (circ_lib => $org_list) unless $local; + + my $circ = $e->search_action_circulation([{ + checkin_time => undef, + target_copy => $copy_id, + %circ_filter + }, $circ_flesh])->[0]; + + if ($circ) { + $next_action = 'ill-foreign-checkin' unless $local; + $resp{circ} = $circ; + } + + my %transit_filter; + + # non-local copies must be coming to / going from "here" to be relevant + $transit_filter{'-or'} = + [{dest => $org_list}, {source => $org_list}] + unless $local; + + # no need to re-fetch transits linked to holds + $transit_filter{id} = {'<>' => $hold->transit->id} + if $hold and $hold->transit; + + my $transit = $e->search_action_transit_copy([{ + target_copy => $copy_id, + dest_recv_time => undef, + %transit_filter + }, $transit_flesh])->[0]; + + if ($transit) { + if ($transit->dest->id == $ctx_ou) { + if ($local) { + $next_action = 'transit-home-receive' + } else { + $next_action = 'transit-foreign-return'; + } + } + $resp{transit} = $transit; + } + + $resp{next_action} = $next_action; + return \%resp; +} + + + 1; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm index b39068891d..db0792804c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm @@ -330,6 +330,7 @@ sub run_method { $circulator->do_renew(); } + my $remote = 0; if( $circulator->bail_out ) { my @ee; @@ -347,6 +348,7 @@ sub run_method { } else { $circulator->editor->commit; + $remote = 1; if ($circulator->generate_lost_overdue) { # Generating additional overdue billings has to happen after the @@ -361,6 +363,78 @@ sub run_method { $circulator->script_runner->cleanup if $circulator->script_runner; + if ($remote) { + my $ff_action = $circulator->ff_action || ''; + my $cl = $circulator->circ_lib; + $cl = $cl->id if (ref $cl); + + # user_barcode is not fleshed (or needed) in all contexts + my $user_barcode = $circulator->patron->card->barcode + if $circulator->patron and $circulator->patron->card; + + $logger->info("circulator: performing FF action '$ff_action'"); + + my $FF = OpenSRF::AppSession->create('fulfillment.laicore'); + + if ($ff_action eq 'ill-home-capture') { + $FF->request( 'fulfillment.laicore.circ.lender.checkout', + $cl, $circulator->copy->barcode )->gather(1); + + } elsif ($ff_action eq 'ill-foreign-receive') { + + # create the temporary copy for the borrower + my $tmp_copy = $FF->request( + 'fulfillment.laicore.item.create_for_borrower', + $cl, $circulator->copy->id)->gather(1); + + if ($tmp_copy) { + my $bc = $tmp_copy->{barcode}; + + $logger->info("circulator: created tmp copy for ". + "borrower, attempting hold placement for $bc at $cl"); + + # place a hold on the temp copy for the borrower + # at the borrowing library + + # ensure the borrower hold is placed against the same + # patron for which the FF hold was captured and transited. + $user_barcode = $circulator->editor->retrieve_actor_user([ + $circulator->hold->usr, + {flesh => 1, flesh_fields => {au => ['card']}} + ])->card->barcode; + + $FF->request( + 'fulfillment.laicore.hold.borrower.place', + $cl, $bc, $user_barcode)->gather(1); + + # check the temp copy in at the borrowing library + # to capture the hold for the patron. + + $FF->request( + 'fulfillment.laicore.circ.borrower.checkin', + $cl, $bc, $user_barcode)->gather(1); + + } else { + + # some connectors may not allow us to create borrower copies. + $logger->info("FF no borrower copy created for copy ". + $circulator->copy->barcode.", skipping borrower library hold"); + } + + } elsif ($ff_action eq 'ill-foreign-checkout') { + $FF->request( 'fulfillment.laicore.circ.borrower.checkout', + $cl, $circulator->copy->barcode, $user_barcode)->gather(1); + + } elsif ($ff_action eq 'ill-foreign-checkin') { + $FF->request( 'fulfillment.laicore.circ.borrower.checkin', + $cl, $circulator->copy->barcode )->gather(1); + + } elsif ($ff_action eq 'transit-home-receive') { + $FF->request( 'fulfillment.laicore.circ.lender.checkin', + $cl, $circulator->copy->barcode )->gather(1); + } + } + return undef if $circulator->bail_out; $circulator->do_hold_notify($circulator->notify_hold) @@ -535,6 +609,7 @@ my @AUTOLOAD_FIELDS = qw/ skip_permit_key skip_deposit_fee skip_rental_fee + ff_action use_booking generate_lost_overdue clear_expired diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm index 9de0fca24e..36a347e90a 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm @@ -781,8 +781,10 @@ sub cancel_hold { return 1; } + my $copy = $e->retrieve_asset_copy($hold->current_copy) if $hold->current_copy; + # If the hold is captured, reset the copy status - if( $hold->capture_time and $hold->current_copy ) { + if( $hold->capture_time and $copy ) { my $copy = $e->retrieve_asset_copy($hold->current_copy) or return $e->die_event; @@ -834,6 +836,26 @@ sub cancel_hold { $U->create_events_for_hook('hold_request.cancel.staff', $hold, $hold->pickup_lib); } + # perform FF tasks after the hold is successfully canceled ------- + # do not block on FF calls. Fire and forget. + + # the hold within the lender ILS is fulfilled the moment the FF hold is + # captured. It makes no sense to cancel the lender-ILS hold after that. + if ($copy and !$hold->capture_time) { + my $ses = OpenSRF::AppSession->create('fulfillment.laicore'); + $ses->request( + 'fulfillment.laicore.hold.lender.delete_earliest', + $copy->source_lib, + $copy->barcode + ); + } + + if ($hold->shelf_time) { + # The requested copy has made it to the borrower and a tmp copy + # has been created w/ a hold. + # TODO: cancel the hold within the borrower ILS on the tmp copy + } + return 1; } @@ -1919,7 +1941,9 @@ sub _reset_hold { my $hid = $hold->id; - if( $hold->capture_time and $hold->current_copy ) { + my $copy = $e->retrieve_asset_copy($hold->current_copy) if $hold->current_copy; + + if( $hold->capture_time and $copy ) { my $copy = $e->retrieve_asset_copy($hold->current_copy) or return $e->die_event; @@ -1962,6 +1986,16 @@ sub _reset_hold { $e->update_action_hold_request($hold) or return $e->die_event; $e->commit; + # TODO: we should only cancel the lender hold + # if the FF hold has not yet been captured ? + if ($copy) { + $U->simplereq( + "fulfillment.laicore", + "fulfillment.laicore.hold.lender.delete_earliest", + $copy->source_lib, $copy->barcode + ); + } + $U->storagereq( 'open-ils.storage.action.hold_request.copy_targeter', undef, $hold->id ); @@ -2499,11 +2533,11 @@ sub create_ranged_org_filter { return () if $depth == $top_org->ou_type->depth; my $org_list = $U->storagereq('open-ils.storage.actor.org_unit.descendants.atomic', $selection_ou, $depth); - %org_filter = (circ_lib => []); - push(@{$org_filter{circ_lib}}, $_->id) for @$org_list; + %org_filter = (circ_lib => {'not in' => []}); + push(@{$org_filter{circ_lib}{'not in'}}, $_->id) for @$org_list; $logger->info("hold org filter at depth $depth and selection_ou ". - "$selection_ou created list of @{$org_filter{circ_lib}}"); + "$selection_ou created list of @{$org_filter{circ_lib}{'not in'}}"); return %org_filter; } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/actor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/actor.pm index 4572dcc869..e545889e5c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/actor.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/actor.pm @@ -150,7 +150,7 @@ use base qw/actor/; __PACKAGE__->table( 'actor_card' ); __PACKAGE__->columns( Primary => qw/id/ ); -__PACKAGE__->columns( Essential => qw/usr barcode active/ ); +__PACKAGE__->columns( Essential => qw/usr barcode active org/ ); #------------------------------------------------------------------------------- package actor::user_access_entry; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm index 30109dbf27..6c63ca998b 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/asset.pm @@ -72,7 +72,7 @@ __PACKAGE__->columns( Essential => qw/call_number barcode creator create_date ed fine_level circulate deposit price ref opac_visible circ_as_type circ_modifier deposit_amount location mint_condition holdable dummy_title dummy_author deleted alert_message - age_protect floating cost status_changed_time active_date/ ); + age_protect floating cost status_changed_time active_date source_lib/ ); #------------------------------------------------------------------------------- package asset::copy_part_map; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/biblio.pm index 732dd9a1da..51f546ab7a 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/biblio.pm @@ -11,7 +11,7 @@ use base qw/biblio/; biblio::record_entry->table( 'biblio_record_entry' ); biblio::record_entry->columns( Essential => qw/id tcn_source tcn_value creator editor create_date edit_date source active quality owner share_depth - deleted marc last_xact_id fingerprint/ ); + deleted marc last_xact_id fingerprint remote_id/ ); #------------------------------------------------------------------------------- package biblio::record_note; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm index 9692f27fb0..d09a9aa955 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm @@ -15,6 +15,8 @@ use OpenILS::Utils::Penalty; use POSIX qw(ceil); use OpenILS::Application::Circ::CircCommon; use OpenILS::Application::AppUtils; +use FulfILLment::AT::Reactor::ItemLoad; +use FulfILLment::AT::Reactor::ItemRefresh; my $U = "OpenILS::Application::AppUtils"; # Used in build_hold_sort_clause(). See the hash %order_by_sprintf_args in @@ -1308,7 +1310,7 @@ sub new_hold_copy_targeter { frozen => 'f', prev_check_time => { '<=' => $expire_threshold }, }, - { order_by => 'selection_depth DESC, request_time,prev_check_time' } ) ]; + { order_by => 'selection_depth, request_time,prev_check_time' } ) ]; # find all the holds holds needing first time targeting push @$holds, action::hold_request->search( @@ -1317,7 +1319,7 @@ sub new_hold_copy_targeter { prev_check_time => undef, frozen => 'f', cancel_time => undef, - { order_by => 'selection_depth DESC, request_time' } ); + { order_by => 'selection_depth, request_time' } ); } else { # find all the holds holds needing first time targeting ONLY @@ -1327,7 +1329,7 @@ sub new_hold_copy_targeter { prev_check_time => undef, cancel_time => undef, frozen => 'f', - { order_by => 'selection_depth DESC, request_time' } ) ]; + { order_by => 'selection_depth, request_time' } ) ]; } } catch Error with { my $e = shift; @@ -1374,6 +1376,8 @@ sub new_hold_copy_targeter { for my $hold (@$holds) { try { + my $old_current_copy = $hold->current_copy; + #start a transaction if needed if ($self->method_lookup('open-ils.storage.transaction.current')->run) { $log->debug("Cleaning up after previous transaction\n"); @@ -1382,6 +1386,7 @@ sub new_hold_copy_targeter { $self->method_lookup('open-ils.storage.transaction.begin')->run( $client ); $log->info("Processing hold ".$hold->id."...\n"); + #first, re-fetch the hold, to make sure it's not captured already $hold->remove_from_object_index(); $hold = action::hold_request->retrieve( $hold->id ); @@ -1439,6 +1444,10 @@ sub new_hold_copy_targeter { ( $lang ? (item_lang => $lang) : () ), ) ) { + + FulfILLment::AT::Reactor::ItemLoad->ByBib( { target => $_->to_fieldmapper } ) + for ( metabib::metarecord->retrieve($hold->target)->source_records ); + my ($rtree) = $self ->method_lookup( 'open-ils.storage.biblio.record_entry.ranged_tree') ->run( $r->id, $hold->selection_ou, $hold->selection_depth ); @@ -1453,6 +1462,11 @@ sub new_hold_copy_targeter { } } } elsif ($hold->hold_type eq 'T') { + + FulfILLment::AT::Reactor::ItemLoad->ByBib( + { target => biblio::record_entry->retrieve($hold->target)->to_fieldmapper } + ); + my ($rtree) = $self ->method_lookup( 'open-ils.storage.biblio.record_entry.ranged_tree') ->run( $hold->target, $hold->selection_ou, $hold->selection_depth ); @@ -1470,6 +1484,11 @@ sub new_hold_copy_targeter { ) if ($cn && @{ $cn->copies }); } } elsif ($hold->hold_type eq 'V') { + + FulfILLment::AT::Reactor::ItemLoad->ByBib( + { target => asset::call_number->retrieve($hold->target)->record->to_fieldmapper } + ); + my ($vtree) = $self ->method_lookup( 'open-ils.storage.asset.call_number.ranged_tree') ->run( $hold->target, $hold->selection_ou, $hold->selection_depth ); @@ -1501,6 +1520,11 @@ sub new_hold_copy_targeter { ) if ($itree && @{ $itree->items }); } elsif ($hold->hold_type eq 'C' || $hold->hold_type eq 'R' || $hold->hold_type eq 'F') { + + FulfILLment::AT::Reactor::ItemRefresh->ByItem( + { target => asset::copy->retrieve($hold->target)->to_fieldmapper } + ); + my $_cp = asset::copy->retrieve($hold->target); push @$all_copies, $_cp if $_cp; } @@ -1631,7 +1655,11 @@ sub new_hold_copy_targeter { $hold ); - $all_copies = [ grep { ''.$_->circ_lib ne $pu_lib && ( $_->status == 0 || $_->status == 7 ) } @good_copies ]; + #$all_copies = [ grep { ''.$_->circ_lib ne $pu_lib && ( $_->status == 0 || $_->status == 7 ) } @good_copies ]; + $all_copies = []; + for my $prox (keys %$prox_list) { + push @$all_copies, @{$$prox_list{$prox}}; + } my $min_prox = [ sort keys %$prox_list ]->[0]; my $best; @@ -1783,6 +1811,31 @@ sub new_hold_copy_targeter { } $self->method_lookup('open-ils.storage.transaction.commit')->run; + + # FF----------------- + my $skip_target = 0; + if ($old_current_copy && $best && ($best->id == $old_current_copy->id)) { # old copy and new copy are the same, leave it alone + $skip_target = 1; + } elsif ($old_current_copy) { # old copy to remotely untarget, since we have a new one + $U->simplereq( + "fulfillment.laicore", + "fulfillment.laicore.hold.lender.delete_earliest", + '' . $old_current_copy->source_lib, + $old_current_copy->barcode + ); + } + + if ($best && !$skip_target) { # new copy to target + $U->simplereq( + "fulfillment.laicore", + "fulfillment.laicore.hold.lender.place", + ''. $best->source_lib, + $best->barcode + ); + } + # FF----------------- + + $log->info("\tProcessing of hold ".$hold->id." complete."); push @successes, diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm index 4dc3e47cb1..df9df5db95 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/asset.pm @@ -789,7 +789,7 @@ sub cn_ranged_tree { actor::org_unit ->db_Main ->selectcol_arrayref( - 'SELECT id FROM actor.org_unit_descendants(?,?)', + 'SELECT id FROM actor.org_unit WHERE id NOT IN (SELECT id FROM actor.org_unit_descendants(?,?))', {}, $ou, $depth @@ -839,7 +839,7 @@ sub issuance_ranged_tree { actor::org_unit ->db_Main ->selectcol_arrayref( - 'SELECT id FROM actor.org_unit_descendants(?,?)', + 'SELECT id FROM actor.org_unit WHERE id NOT IN (SELECT id FROM actor.org_unit_descendants(?,?))', {}, $ou, $depth diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm index 8d8648d52e..a211fdcdd0 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/biblio.pm @@ -120,8 +120,8 @@ sub record_ranged_tree { my $offset = shift || 0; my $ou_sql = defined($depth) ? - "SELECT id FROM actor.org_unit_descendants(?,?)": - "SELECT id FROM actor.org_unit_descendants(?)"; + "SELECT id FROM actor.org_unit WHERE id NOT IN (SELECT id FROM actor.org_unit_descendants(?,?))": + "SELECT id FROM actor.org_unit WHERE id NOT IN (SELECT id FROM actor.org_unit_descendants(?))"; my $ou_list = actor::org_unit @@ -209,6 +209,21 @@ __PACKAGE__->register_method( cachable => 1, ); +sub purge_bibs_by_owner { + my $self = shift; + my $client = shift; + my $owner = ''.shift; + + return biblio::record_entry->db_Main->do( 'DELETE FROM biblio.record_entry WHERE owner = ?', {}, $owner ); +} +__PACKAGE__->register_method( + api_name => 'open-ils.storage.biblio.record_entry.purge_by_owner', + method => 'purge_bibs_by_owner', + api_level => 1, + argc => 1, + cachable => 1, +); + sub record_by_copy { my $self = shift; my $client = shift;