From 370d077b102102072de1fb3fcccded510f6d1eb4 Mon Sep 17 00:00:00 2001 From: Jason Stephenson Date: Sun, 21 Sep 2014 15:26:10 -0400 Subject: [PATCH] Add checkoutitem to NCIP::ILS::Evergreen. Also add a couple of utility methods to check if a copy is allowed to circulate and fill holds, as well as one to retrieve a copy location object by id. Signed-off-by: Jason Stephenson --- lib/NCIP/ILS/Evergreen.pm | 223 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/lib/NCIP/ILS/Evergreen.pm b/lib/NCIP/ILS/Evergreen.pm index d619109..bb838b0 100644 --- a/lib/NCIP/ILS/Evergreen.pm +++ b/lib/NCIP/ILS/Evergreen.pm @@ -812,6 +812,165 @@ sub renewitem { return $response; } +=head2 checkoutitem + + $response = $ils->checkoutitem($request); + +Handle the Checkoutitem message. + +=cut + +sub checkoutitem { + my $self = shift; + my $request = shift; + + # Check our session and login if necessary: + $self->login() unless ($self->checkauth()); + + # Common stuff: + my $message = $self->parse_request_type($request); + my $response = NCIP::Response->new({type => $message . 'Response'}); + $response->header($self->make_header($request)); + + # We need the copy barcode from the message. + my ($item_barcode, $item_idfield) = $self->find_item_barcode($request); + if (ref($item_barcode) eq 'NCIP::Problem') { + $response->problem($item_barcode); + return $response; + } + + # Retrieve the copy details. + my $details = $self->retrieve_copy_details_by_barcode($item_barcode); + unless ($details) { + # Return an Unkown Item problem unless we find the copy. + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Unknown Item', + ProblemDetail => "Item with barcode $item_barcode is not known.", + ProblemElement => $item_idfield, + ProblemValue => $item_barcode + } + ) + ); + return $response; + } + + # User is required for CheckOutItem. + my ($user_barcode, $user_idfield) = $self->find_user_barcode($request); + if (ref($user_barcode) eq 'NCIP::Problem') { + $response->problem($user_barcode); + return $response; + } + my $user = $self->retrieve_user_by_barcode($user_barcode, $user_idfield); + if (ref($user) eq 'NCIP::Problem') { + $response->problem($user); + return $response; + } + + # Isolate the copy. + my $copy = $details->{copy}; + + # Check if the copy can circulate. + unless ($self->copy_can_circulate($copy)) { + $reponse->problem( + NCIP::Problem->new( + { + ProblemType => 'Item Does Not Circulate', + ProblemDetail => "Item with barcode $item_barcode does not circulate.", + ProblemElement => $item_idfield, + ProblemValue => $item_barcode + } + ) + ); + return $response; + } + + # Look for a circulation and examine its information: + my $circ = $details->{circ}; + + # Check if the item is already checked out. + if ($circ && !$circ->checkin_time()) { + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Item Already Checked Out', + ProblemDetail => "Item with barcode $item_barcode is already checked out.", + ProblemElement => $item_idfield, + ProblemValue => $item_barcode + } + ) + ); + return $response; + } + + # Check if user is blocked from circulation: + my $problem = $self->check_user_for_problems($user, 'CIRC'); + if ($problem) { + # Replace the ProblemElement and ProblemValue fields. + $problem->ProblemElement($user_idfield); + $problem->ProblemValue($user_barcode); + $response->problem($problem); + return $response; + } + + # Now, we attempt the check out. If it fails, we simply say that + # the user is not allowed to check out this item, without getting + # into details. + my $params = { + copy => $copy, + patron_id => $user->id(), + }; + my $r = $U->simplereq( + 'open-ils.circ', + 'open-ils.circ.checkout.full.override', + $self->{session}->{authtoken}, + $params + )->gather(1); + + # We only look at the first one, since more than one usually means + # failure. + if (ref($r) eq 'ARRAY') { + $r = $r->[0]; + } + if ($r->{textcode} ne 'SUCCESS') { + $problem = _problem_from_event('Check Out Failed', $r); + $response->problem($problem); + } else { + my $data = { + ItemId => NCIP::Item::Id->new( + { + AgencyId => $request->{$message}->{ItemId}->{AgencyId}, + ItemIdentifierType => $request->{$message}->{ItemId}->{ItemIdentifierType}, + ItemIdentifierValue => $request->{$message}->{ItemId}->{ItemIdentifierValue} + } + ), + UserId => NCIP::User::Id->new( + { + UserIdentifierType => 'Barcode Id', + UserIdentifierValue => $user->card->barcode() + } + ) + }; + # We need to retrieve the copy details again to refresh our + # circ information to get the due date. + $details = $self->retrieve_copy_details_by_barcode($item_barcode); + $circ = $details->{circ}; + my $due = DateTime::Format::ISO8601->parse_datetime(cleanse_ISO8601($circ->due_date())); + $due->set_time_zone('UTC'); + $data->{DateDue} = $due->iso8601(); + + $response->data($data); + } + + # At some point in the future, we should probably check if + # they requested optional user or item elements and return + # those. For the time being, we ignore those at the risk of + # being considered non-compliant. + + return $response; +} + =head1 METHODS USEFUL to SUBCLASSES =head2 login @@ -1142,6 +1301,28 @@ sub retrieve_org_unit_by_shortname { return $aou; } +=head2 retrieve_copy_location + + $location = $ils->retrieve_copy_location($location_id); + +Retrive a copy location based on id. + +=cut + +sub retrieve_copy_location { + my $self = shift; + my $id = shift; + + my $location = $U->simplereq( + 'open-ils.pcrud', + 'open-ils.pcrud.retrieve.acpl', + $self->{session}->{authtoken}, + $id + ); + + return $location; +} + =head2 create_precat_copy $item_info->{ @@ -1546,6 +1727,48 @@ sub delete_copy { return undef; } +=head2 copy_can_circulate + + $can_circulate = $ils->copy_can_circulate($copy); + +Check if the copy's location and the copy itself allow +circulation. Return true if they do, and false if they do not. + +=cut + +sub copy_can_circulate { + my $self = shift; + my $copy = shift; + + my $location = $copy->location(); + unless (ref($location)) { + $location = $self->retrieve_copy_location($location); + } + + return ($U->is_true($copy->circulate()) && $U->is_true($location->circulate())); +} + +=head2 copy_can_fulfill + + $can_fulfill = $ils->copy_can_fulfill($copy); + +Check if the copy's location and the copy itself allow +holds. Return true if they do, and false if they do not. + +=cut + +sub copy_can_fulfill { + my $self = shift; + my $copy = shift; + + my $location = $copy->location(); + unless (ref($location)) { + $location = $self->retrieve_copy_location($location); + } + + return ($U->is_true($copy->holdable()) && $U->is_true($location->holdable())); +} + =head1 OVERRIDDEN PARENT METHODS =head2 find_user_barcode -- 2.43.2