From: miker Date: Thu, 10 Dec 2009 17:10:11 +0000 (+0000) Subject: add first version of the booking reservation targeter X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=1ac899fc20934df4752ac9e9b16b4806491d3ae9;p=evergreen%2Fbjwebb.git add first version of the booking reservation targeter git-svn-id: svn://svn.open-ils.org/ILS/trunk@15133 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm index c2b0f5684..419179c9f 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm @@ -557,6 +557,12 @@ sub modify_from_fieldmapper { action::circulation->has_a( usr => 'actor::user' ); actor::user->has_many( circulations => 'action::circulation' => 'usr' ); + booking::resource_attr_map->has_a( resource => 'booking::resource' ); + + booking::resource->has_a( owner => 'actor::org_unit' ); + booking::resource->has_a( type => 'booking::resource_type' ); + booking::resource_type->has_a( owner => 'actor::org_unit' ); + booking::reservation->has_a( usr => 'actor::user' ); actor::user->has_many( reservations => 'booking::reservation' => 'usr' ); diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm index 7a7bb362b..811ad378f 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/booking.pm @@ -6,6 +6,24 @@ package booking; use base qw/OpenILS::Application::Storage::CDBI/; #------------------------------------------------------------------------------- +package booking::resource_type; +use base qw/booking/; +__PACKAGE__->table('booking_resource_type'); +__PACKAGE__->columns(Primary => 'id'); +__PACKAGE__->columns(Essential => qw/name fine_interval fine_amount + max_fine owner catalog_item record transferable elbow_room/); + +#------------------------------------------------------------------------------- + +package booking::resource; +use base qw/booking/; +__PACKAGE__->table('booking_resource'); +__PACKAGE__->columns(Primary => 'id'); +__PACKAGE__->columns(Essential => qw/owner type overbook barcode deposit + deposit_amount user_fee/); + +#------------------------------------------------------------------------------- + package booking::reservation; use base qw/booking/; __PACKAGE__->table('booking_reservation'); @@ -19,5 +37,21 @@ __PACKAGE__->columns(Essential => qw/xact_start usr current_copy circ_lib #------------------------------------------------------------------------------- +package booking::resource_attr_map; +use base qw/booking/; +__PACKAGE__->table('booking_resource_attr_map'); +__PACKAGE__->columns(Primary => 'id'); +__PACKAGE__->columns(Essential => qw/resource resource_attr value/); + +#------------------------------------------------------------------------------- + +package booking::reservation_attr_value_map; +use base qw/booking/; +__PACKAGE__->table('booking_reservation_attr_value_map'); +__PACKAGE__->columns(Primary => 'id'); +__PACKAGE__->columns(Essential => qw/reservation attr_value/); + +#------------------------------------------------------------------------------- + 1; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm index 9939f5a42..a3fd66e10 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm @@ -161,12 +161,36 @@ action::circulation->sequence( 'money.billable_xact_id_seq' ); #--------------------------------------------------------------------- + package booking::resource_type; + + booking::resource_type->table( 'booking.resource_type' ); + booking::resource_type->sequence( 'booking.resource_type_id_seq' ); + + #--------------------------------------------------------------------- + package booking::resource; + + booking::resource->table( 'booking.resource' ); + booking::resource->sequence( 'booking.resource_id_seq' ); + + #--------------------------------------------------------------------- package booking::reservation; booking::reservation->table( 'booking.reservation' ); booking::reservation->sequence( 'money.billable_xact_id_seq' ); #--------------------------------------------------------------------- + package booking::reservation_attr_value_map; + + booking::reservation_attr_value_map->table( 'booking.reservation_attr_value_map' ); + booking::reservation_attr_value_map->sequence( 'booking.reservation_attr_value_map_id_seq' ); + + #--------------------------------------------------------------------- + package booking::resource_attr_map; + + booking::resource_attr_map->table( 'booking.resource_attr_map' ); + booking::resource_attr_map->sequence( 'booking.resource_attr_map_id_seq' ); + + #--------------------------------------------------------------------- package action::non_cat_in_house_use; action::non_cat_in_house_use->table( 'action.non_cat_in_house_use' ); diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm index 6785a7566..375d5982b 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/action.pm @@ -1320,6 +1320,205 @@ __PACKAGE__->register_method( method => 'new_hold_copy_targeter', ); +sub reservation_targeter { + my $self = shift; + my $client = shift; + my $one_reservation = shift; + + local $OpenILS::Application::Storage::WRITE = 1; + + my $reservations; + + try { + if ($one_reservation) { + $self->method_lookup('open-ils.storage.transaction.begin')->run( $client ); + $reservations = booking::reservation->search_where( { id => $one_reservation, capture_time => undef, cancel_time => undef } ); + } else { + + # find all the reservations needing targeting + $reservations = [ + booking::reservation->search_where( + { current_resource => undef, + cancel_time => undef, + start_time => { '>' => 'now' } + }, + { order_by => 'start_time' } + ) + ]; + } + } catch Error with { + my $e = shift; + die "Could not retrieve reservation requests:\n\n$e\n"; + }; + + for my $bresv (@$reservations) { + try { + #start a transaction if needed + if ($self->method_lookup('open-ils.storage.transaction.current')->run) { + $log->debug("Cleaning up after previous transaction\n"); + $self->method_lookup('open-ils.storage.transaction.rollback')->run; + } + $self->method_lookup('open-ils.storage.transaction.begin')->run( $client ); + $log->info("Processing reservation ".$bresv->id."...\n"); + + #first, re-fetch the hold, to make sure it's not captured already + $bresv->remove_from_object_index(); + $bresv = booking::reservation->retrieve( $bresv->id ); + + die "OK\n" if (!$bresv or $bresv->capture_time or $bresv->cancel_time); + + my $end_time = $parser->parse_datetime( clense_ISO8601( $bresv->end_time ) ); + if (DateTime->compare($end_time, DateTime->now) < 0) { + + # cancel cause = un-targeted expiration + $bresv->update( { cancel_time => 'now' } ); + $self->method_lookup('open-ils.storage.transaction.commit')->run; + + # tell A/T the reservation was cancelled + my $fm_bresv = $bresv->to_fieldmapper; + my $ses = OpenSRF::AppSession->create('open-ils.trigger'); + $ses->request('open-ils.trigger.event.autocreate', + 'booking.reservation.cancel.expire_no_target', $fm_bresv, $fm_bresv->pickup_lib); + + die "OK\n"; + } + + my $possible_resources; + + # find all the potential resources + if (!$bresv->target_resource) { + my $filter = { type => $bresv->target_resource_type }; + my $attr_maps = booking::reservations_attr_value_map->search( reservation => $bresv->id ); + + $filter->{attribute_values} = [ map { $_->attr_value } @$attr_maps ] if (@$attr_maps); + + my $ses = OpenSRF::AppSession->create('open-ils.booking'); + $possible_resources = $ses->request('open-ils.booking.resources.filtered_id_list', $filter)->gather(1); + + } else { + $possible_resources = $bresv->target_resource; + } + + my $all_resources booking::resource->search( id => $possible_resources ); + @$all_resources = grep { isTrue($_->type->transferable) || $_->owner.'' eq $bresv->pickup_lib.'' } @$all_resources; + + + my @good_resources; + for my $res (@$all_resources) { + unless (isTrue($res->type->catalog_item)) { + push @good_resources, $res; + next; + } + + my $copy = asset::copy->search( deleted => f, barcode => $res->barcode )->[0]; + + unless ($copy) { + push @good_resources, $res; + next; + } + + if ($copy->status->id == 0 || $copy->status->id == 7) { + push @good_resources, $res; + next; + } + + if ($copy->status->id == 1) { + my $circs = action::circulation->search_where( + {target_copy => $copy->id, checkin_time => undef }, + { order_by => 'id DESC' } + ); + + if (@$circs) { + my $due_date = $circs->[0]->due_date; + $due_date = $parser->parse_datetime( clense_ISO8601( $due_date ) ); + my $start_time = $parser->parse_datetime( clense_ISO8601( $bresv->start_time ) ); + next if (DateTime->compare($start_time, $due_date) < 0); + push @good_resources, $res; + } + + next; + } + + push @good_resources, $res if (isTrue($copy->status->holdable)); + } + + # let 'em know we're still working + $client->status( new OpenSRF::DomainObject::oilsContinueStatus ); + + # if we have no copies ... + if (!@good_resources) { + $log->info("\tNo resources available for targeting at all!\n"); + push @successes, { reservation => $bresv->id, eligible_copies => 0, error => 'NO_COPIES' }; + + $self->method_lookup('open-ils.storage.transaction.commit')->run; + die "OK\n"; + } + + $log->debug("\t".scalar(@good_resources)." resources available for targeting..."); + + my $prox_list = []; + $$prox_list[0] = + [ + grep { + $_->owner == $bresv->pickup_lib + } @good_resources + ]; + + $all_resources = [grep {$_->owner != $bresv->pickup_lib } @good_resources]; + # $all_copies is now a list of copies not at the pickup library + + my $best = shift @good_resources; + $client->status( new OpenSRF::DomainObject::oilsContinueStatus ); + + if (!$best) { + $log->debug("\tNothing at the pickup lib, looking elsewhere among ".scalar(@$all_resources)." resources"); + + $prox_list = + map { $_->[1] } + sort { $a->[0] <> $b->[0] } + map { + [ actor::org_unit_proximity->search_where( + { from_org => $bresv->pickup_lib.'', to_org => $_=>owner.'' } + )->[0]->prox, + $_ + ] + } @$all_resources; + + $client->status( new OpenSRF::DomainObject::oilsContinueStatus ); + + $best = shift @$prox_list + } + + if ($best) { + $bresv->update( { current_resource => ''.$best->id } ); + $log->debug("\tUpdating reservation [".$bresv->id."] with new 'current_resource' [".$best->id."] for reservation fulfillment."); + } + + $self->method_lookup('open-ils.storage.transaction.commit')->run; + $log->info("\tProcessing of hold ".$hold->id." complete."); + + push @successes, + { reservation => $hold->id, + current_resource => ($best ? $best->id : undef) }; + + } otherwise { + my $e = shift; + if ($e !~ /^OK/o) { + $log->error("Processing of hold failed: $e"); + $self->method_lookup('open-ils.storage.transaction.rollback')->run; + throw $e if ($e =~ /IS NOT CONNECTED TO THE NETWORK/o); + } + }; + } + + return \@successes; +} +__PACKAGE__->register_method( + api_name => 'open-ils.storage.booking.reservation.resource_targeter', + api_level => 1, + method => 'reservation_targeter', +); + my $locations; my $statuses; my %cache = (titles => {}, cns => {});