From e209668a1f6fcc3106411b97b091802670810312 Mon Sep 17 00:00:00 2001 From: Jason Stephenson Date: Sun, 28 Sep 2014 10:19:45 -0400 Subject: [PATCH] Add cancelrequestitem handler to NCIP::ILS::Evergreen. Also add the CancelRequestItemResponse.inc to the templates. Signed-off-by: Jason Stephenson --- lib/NCIP/ILS/Evergreen.pm | 305 +++++++++++++++++- .../includes/CancelRequestItemResponse.inc | 18 ++ 2 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 templates/includes/CancelRequestItemResponse.inc diff --git a/lib/NCIP/ILS/Evergreen.pm b/lib/NCIP/ILS/Evergreen.pm index 5d588b3..fd19d33 100644 --- a/lib/NCIP/ILS/Evergreen.pm +++ b/lib/NCIP/ILS/Evergreen.pm @@ -520,7 +520,7 @@ sub checkinitem { # 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. + # Return an Unknown Item problem unless we find the copy. $response->problem( NCIP::Problem->new( { @@ -655,7 +655,7 @@ sub renewitem { # 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. + # Return an Unknown Item problem unless we find the copy. $response->problem( NCIP::Problem->new( { @@ -842,7 +842,7 @@ sub checkoutitem { # 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. + # Return an Unknown Item problem unless we find the copy. $response->problem( NCIP::Problem->new( { @@ -1032,7 +1032,7 @@ sub requestitem { # Retrieve the copy details. my $copy_details = $self->retrieve_copy_details_by_barcode($item_barcode); unless ($copy_details) { - # Return an Unkown Item problem unless we find the copy. + # Return an Unknown Item problem unless we find the copy. $response->problem( NCIP::Problem->new( { @@ -1114,6 +1114,220 @@ sub requestitem { return $response; } +=head2 cancelrequestitem + + $response = $ils->cancelrequestitem($request); + +Handle the NCIP CancelRequestItem message. + +=cut + +sub cancelrequestitem { + 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)); + + # UserId is required by the standard, but we might not really need it. + 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; + } + + # See if we got a ItemId and a barcode: + my $copy_details; + my ($item_barcode, $item_idfield) = $self->find_item_barcode($request); + if (ref($item_barcode) ne 'NCIP::Problem') { + # Retrieve the copy details. + $copy_details = $self->retrieve_copy_details_by_barcode($item_barcode); + unless ($copy_details) { + # Return an Unknown 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; + } + } + + # See if we got a RequestId: + my $requestid; + if ($request->{$message}->{RequestId}) { + $requestid = NCIP::RequestId->new( + { + AgencyId => $request->{$message}->{RequestId}->{AgencyId}, + RequestIdentifierType => $request->{$message}->{RequestId}->{RequestIdentifierType}, + RequestIdentifierValue => $request->{$message}->{RequestId}->{RequestIdentifierValue} + } + ) + } + + # Just a note: In the below, we cannot rely on the hold or transit + # fields of the copy_details, even if we have retrieved it. This + # is because that hold and transit may not be the ones that we're + # looking for, i.e. they could be for another patron, etc. + + # See if we can find the hold: + my $hold; + if ($requestid) { + $hold = $U->simplereq( + 'open-ils.pcrud', + 'open-ils.pcrud.retrieve.ahr', + $self->{session}->{authtoken}, + $requestid->{RequestIdentifierValue}, + {flesh => 1, flesh_fields => {ahr => ['transit']}} + ); + unless ($hold) { + # Report a problem that we couldn't find a hold by that id. + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Unknown Request', + ProblemDetail => 'No request with this identifier found', + ProblemElement => 'RequestIdentifierValue', + ProblemValue => $requestid->{RequestIdentifierValue} + } + ) + ) + } elsif ($hold->cancel_time()) { + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Request Already Canceled', + ProblemDetail => 'Request has already been canceled', + ProblemElement => 'RequestIdentifierValue', + ProblemValue => $requestid->{RequestIdentifierValue} + } + ) + ) + } elsif ($hold->transit()) { + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Request Already Processed', + ProblemDetail => 'Request has already been processed', + ProblemElement => 'RequestIdentifierValue', + ProblemValue => $requestid->{RequestIdentifierValue} + } + ) + ) + } elsif ($hold->usr() == $user->id()) { + # Check the target matches the copy information, if any, + # that we were given. + my $obj_id; + if ($copy_details) { + if ($hold->hold_type() eq 'V') { + $obj_id = $copy_details->{volume}->id(); + } elsif ($hold->hold_type() eq 'T') { + $obj_id = $copy_details->{mvr}->doc_id(); + } elsif ($hold->hold_type() eq 'C' || $hold->hold_type() eq 'F') { + $obj_id = $copy_details->{copy}->id(); + } + } + if ($obj_id && $hold->target() != $obj_id) { + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Request Not For This Item', + ProblemDetail => "Request is not for this item", + ProblemElement => $item_idfield, + ProblemElement => $item_barcode + } + ) + ) + } else { + $self->cancel_hold($hold); + $response->data( + { + RequestId => $requestid, + UserId => NCIP::User::Id->new( + { + UserIdentifierType => 'Barcode Id', + UserIdentifierValue => $user->card->barcode() + } + ) + } + ) + } + } else { + # Report a problem that the hold is not for this user. + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Request Not For This User', + ProblemDetail => 'Request is not for this user.', + ProblemElement => $user_idfield, + ProblemValue => $user_barcode + } + ) + ) + } + } else { + # At this point, we *must have* an ItemId and therefore + # $copy_details, so return the problem from looking up the + # barcode if we don't have $copy_details. + if (!$copy_details) { + $response->problem($item_barcode); + } else { + # We have to search for the hold based on the copy details and + # the user. We'll need to search for copy (or force) holds, a + # volume hold, or a title hold. + $hold = $self->_hold_search($user, $copy_details); + if (ref($hold) eq 'NCIP::Problem') { + $response->problem($hold); + } elsif ($hold->transit()) { + $response->problem( + NCIP::Problem->new( + { + ProblemType => 'Request Already Processed', + ProblemDetail => 'Request has already been processed', + ProblemElement => 'RequestIdentifierValue', + ProblemValue => $requestid->{RequestIdentifierValue} + } + ) + ) + } else { + $self->cancel_hold($hold); + $response->data( + { + RequestId => NCIP::RequestId->new( + { + RequestIdentifierType => 'SYSNUMBER', + RequestIdentifierValue => $hold->id() + } + ), + UserId => NCIP::User::Id->new( + { + UserIdentifierType => 'Barcode Id', + UserIdentifierValue => $user->card->barcode() + } + ) + } + ) + } + } + } + + return $response; +} + =head1 METHODS USEFUL to SUBCLASSES =head2 login @@ -1879,6 +2093,36 @@ sub place_hold { return $hold; } +=head2 cancel_hold + + $ils->cancel_hold($hold); + +This method cancels the hold argument. It makes no checks on the hold, +so if there are certain conditions that need to be fulfilled before +the hold is canceled, then you must check them before calling this +method. + +It returns undef on success or failure. If it fails, you've usually +got bigger problems. + +=cut + +sub cancel_hold { + my $self = shift; + my $hold = shift; + + my $r = $U->simplereq( + 'open-ils.circ', + 'open-ils.circ.hold.cancel', + $self->{session}->{authtoken}, + $hold->id(), + '5', + 'Canceled via NCIPServer' + ); + + return undef; +} + =head2 delete_copy $ils->delete_copy($copy); @@ -2295,6 +2539,59 @@ sub _bib_search { return $item; } +# Search for holds using the user and copy_details information: +sub _hold_search { + my $self = shift; + my $user = shift; + my $copy_details = shift; + + my $hold; + + # Retrieve all of the user's uncanceled, unfulfilled holds, and + # then search them in Perl. + my $holds_list = $U->simplereq( + 'open-ils.circ', + 'open-ils.circ.holds.retrieve', + $self->{session}->{authtoken}, + $user->id(), + 0 + ); + + if ($holds_list && @$holds_list) { + my @holds; + # Look for title holds (the most common), first: + my $targetid = $copy_details->{mvr}->doc_id(); + @holds = grep {$_->hold_type eq 'T' && $_->target == $targetid} @{$holds_list}; + unless (@holds) { + # Look for volume holds, the next most common: + $targetid = $copy_details->{volume}->id(); + @holds = grep {$_->hold_type eq 'V' && $_->target == $tagetid} @{$holds_list}; + } + unless (@holds) { + # Look for copy and force holds, the least likely. + $targetid = $copy_details->{copy}->id(); + @holds = grep {($_->hold_type eq 'C' || $_->hold_type eq 'F') && $_->target == $targetid} @{$holds_list}; + } + # There should only be 1, at this point, if there are any. + if (@holds) { + $hold = $holds[0]; + } + } + + unless ($hold) { + $hold = NCIP::Problem->new( + { + ProblemType => 'Unknown Request', + ProblemDetail => 'Request matching the user and item not found.', + ProblemElement => 'NULL', + ProblemValue => 'NULL' + } + ) + } + + return $hold; +} + # Standalone, "helper" functions. These do not take an object or # class reference. diff --git a/templates/includes/CancelRequestItemResponse.inc b/templates/includes/CancelRequestItemResponse.inc new file mode 100644 index 0000000..483e63b --- /dev/null +++ b/templates/includes/CancelRequestItemResponse.inc @@ -0,0 +1,18 @@ + +[% IF data.RequestId.AgencyId -%] +[% data.RequestId.AgencyId | xml %] +[% END -%] +[% data.RequestId.RequestIdentifierValue | xml %] +[% IF data.RequestId.RequestIdentifierType -%] +[% data.RequestId.RequestIdentifierType | xml %] +[% END %] + + +[% IF data.UserId.AgencyId -%] +[% data.UserId.AgencyId | xml %] +[% END -%] +[% data.UserId.UserIdentifierValue | xml %] +[% IF data.UserId.UserIdentifierType -%] +[% data.UserId.UserIdentifierType | xml %] +[% END -%] + -- 2.43.2