From 37fefedb998fd2fc6b970daaa6b9adbb4de8f548 Mon Sep 17 00:00:00 2001 From: jirislav Date: Mon, 13 Apr 2015 12:23:55 +0200 Subject: [PATCH] Bug 13930 - Created NCIP svc to effectively parse data from database to JSON in order to query those from xcncip2toolkit koha's connector --- C4/NCIP/CancelRequestItem.pm | 100 ++++++++++++++++++++ C4/NCIP/LookupItem.pm | 168 +++++++++++++++++++++++++++++++++ C4/NCIP/LookupItemSet.pm | 212 ++++++++++++++++++++++++++++++++++++++++++ C4/NCIP/LookupRequest.pm | 85 +++++++++++++++++ C4/NCIP/LookupUser.pm | 192 ++++++++++++++++++++++++++++++++++++++ C4/NCIP/NcipUtils.pm | 199 +++++++++++++++++++++++++++++++++++++++ C4/NCIP/RenewItem.pm | 147 +++++++++++++++++++++++++++++ C4/NCIP/RequestItem.pm | 194 ++++++++++++++++++++++++++++++++++++++ C4/Reserves.pm | 53 ++++++++++- svc/ncip | 79 ++++++++++++++++ 10 files changed, 1428 insertions(+), 1 deletion(-) create mode 100644 C4/NCIP/CancelRequestItem.pm create mode 100644 C4/NCIP/LookupItem.pm create mode 100644 C4/NCIP/LookupItemSet.pm create mode 100644 C4/NCIP/LookupRequest.pm create mode 100644 C4/NCIP/LookupUser.pm create mode 100644 C4/NCIP/NcipUtils.pm create mode 100644 C4/NCIP/RenewItem.pm create mode 100644 C4/NCIP/RequestItem.pm create mode 100755 svc/ncip diff --git a/C4/NCIP/CancelRequestItem.pm b/C4/NCIP/CancelRequestItem.pm new file mode 100644 index 0000000..3cbe755 --- /dev/null +++ b/C4/NCIP/CancelRequestItem.pm @@ -0,0 +1,100 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::CancelRequestItem; + +use Modern::Perl; + +=head1 NAME + +C4::NCIP::CancelRequestItem - NCIP module for effective processing of CancelRequestItem NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::CancelRequestItem; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 cancelRequestItem + + cancelRequestItem($cgiInput) + + Expected input is as e.g. as follows: + + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=cancel_request_item&requestId=89&userId=4 + or + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=cancel_request_item&itemId=95&userId=3 + + REQUIRED PARAMS: + Param 'service=cancel_request_item' tells svc/ncip to forward the query here. + Param 'userId=3' specifies borrowernumber whos request is being cancelled. + Param 'itemId=4' specifies itemnumber to cancel. + Param 'requestId=89' specifies request to cancel. + +=cut + +sub cancelRequestItem { + my ($query) = @_; + my $userId = $query->param('userId'); + my $itemId = $query->param('itemId'); + my $requestId = $query->param('requestId'); + my ($result, $reserve); + if (defined $userId and defined $itemId) { + $reserve + = C4::Reserves::GetReserveFromBorrowernumberAndItemnumber($userId, + $itemId); + + } elsif (defined $userId and defined $requestId) { + $reserve = C4::Reserves::GetReserve($requestId); + } else { + C4::NCIP::NcipUtils::print400($query, + 'You have to specify either both \'userId\' & \'itemId\' or both \'userId\' & \'requestId\'..' + ); +# It's a shame schema allow RequestItem with BibId & doesn't allow CancelRequestItem with BibId .. (NCIP Initiatior needs to LookupUser with RequestedItemsDesired -> parse requestId of bibId) +# +# Schema definition of CancelRequestItem: +# +# +# Source: http://www.niso.org/schemas/ncip/v2_02/ncip_v2_02.xsd + } + + C4::NCIP::NcipUtils::print404($query, "Request not found..") + unless $reserve; + + C4::NCIP::NcipUtils::print403($query, + 'Request doesn\'t belong to this patron ..') + unless $reserve->{'borrowernumber'} eq $userId; + + C4::Reserves::CancelReserve($reserve); + + $result->{'userId'} = $reserve->{borrowernumber}; + $result->{'itemId'} = $reserve->{itemnumber}; + $result->{'requestId'} = $reserve->{reserve_id}; + $result->{'status'} = 'cancelled'; + + C4::NCIP::NcipUtils::printJson($query, $result); +} + +1; diff --git a/C4/NCIP/LookupItem.pm b/C4/NCIP/LookupItem.pm new file mode 100644 index 0000000..79ead12 --- /dev/null +++ b/C4/NCIP/LookupItem.pm @@ -0,0 +1,168 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::LookupItem; + +use Modern::Perl; +use C4::NCIP::NcipUtils; + +=head1 NAME + +C4::NCIP::LookupItem - NCIP module for effective processing of LookupItem NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::LookupItem; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 lookupItem + + lookupItem($cgiInput) + + Expected input is as e.g. as follows: + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_item&itemId=95&holdQueueLengthDesired&circulationStatusDesired&itemUseRestrictionTypeDesired¬ItemInfo + or + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_item&itemId=95 + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_item&barcode=956216 + + REQUIRED PARAMS: + Param 'service=lookup_item' tells svc/ncip to forward the query here. + Param 'itemId=4' specifies itemnumber to look for. + Param 'barcode=956216' specifies barcode to look for. + + OPTIONAL PARAMS: + holdQueueLengthDesired specifies to include number of reserves placed on item + circulationStatusDesired specifies to include circulation statuses of item + itemUseRestrictionTypeDesired specifies to inlude item use restriction type of item + notItemInfo specifies to omit item information (normally returned) +=cut + +sub lookupItem { + my ($query) = @_; + + my $itemId = $query->param('itemId'); + my $barcode = $query->param('barcode'); + + unless (defined $itemId) { + C4::NCIP::NcipUtils::print400($query, + "itemId nor barcode is specified..\n") + unless $barcode; + + $itemId = C4::Items::GetItemnumberFromBarcode($barcode); + } + + my $iteminfo = C4::Items::GetItem($itemId, $barcode, undef); + + C4::NCIP::NcipUtils::print404($query, "Item not found..") + unless $iteminfo; + + my $bibId = $iteminfo->{'biblioitemnumber'}; + + my $result; + my $desiredSomething = 0; + if ( defined $query->param('holdQueueLengthDesired') + or defined $query->param('circulationStatusDesired')) + { + $desiredSomething = 1; + + my $holds = C4::Reserves::GetReserveCountFromItemnumber($itemId); + + if (defined $query->param('holdQueueLengthDesired')) { + $result->{'holdQueueLength'} = $holds; + } + if (defined $query->param('circulationStatusDesired')) { + $result->{'circulationStatus'} + = C4::NCIP::NcipUtils::parseCirculationStatus($iteminfo, + $holds); + } + } + if (defined $query->param('itemUseRestrictionTypeDesired')) { + my $restrictions + = C4::NCIP::NcipUtils::parseItemUseRestrictions($iteminfo); + unless (scalar @{$restrictions} == 0) { + $result->{'itemUseRestrictions'} = $restrictions; + } + $desiredSomething = 1; + } + + $result->{'itemInfo'} = parseItem($bibId, $itemId, $iteminfo) + unless $desiredSomething and defined $query->param('notItemInfo'); + + C4::NCIP::NcipUtils::printJson($query, $result); +} + +=head2 parseItem + + parseItem($biblionumber, $itemnumber, $item) + + Returns info of biblio level & item level + +=cut + +sub parseItem { + my ($bibId, $itemId, $item) = @_; + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(" + SELECT biblioitems.volume, + biblioitems.number, + biblioitems.isbn, + biblioitems.issn, + biblioitems.publicationyear, + biblioitems.publishercode, + biblioitems.pages, + biblioitems.size, + biblioitems.place, + biblioitems.agerestriction, + biblio.author, + biblio.title, + biblio.unititle, + biblio.notes, + biblio.serial + FROM biblioitems + LEFT JOIN biblio ON biblio.biblionumber = biblioitems.biblionumber + WHERE biblioitems.biblionumber = ?"); + $sth->execute($bibId); + my $result = $sth->fetchrow_hashref; + + return 'SQL query failed' unless $result; + + $result->{itemId} = $itemId; + $result->{bibId} = $bibId; + $result->{barcode} = $item->{barcode}; + $result->{location} = $item->{location}; + $result->{homebranch} = $item->{homebranch}; + $result->{restricted} = $item->{restricted}; + $result->{holdingbranch} = $item->{holdingbranch}; + $result->{mediumtype} = $item->{itype}; + $result->{copynumber} = $item->{copynumber}; + $result->{callnumber} = $item->{itemcallnumber}; + $result->{ccode} = $item->{ccode}; + + return C4::NCIP::NcipUtils::clearEmptyKeys($result); +} + +1; diff --git a/C4/NCIP/LookupItemSet.pm b/C4/NCIP/LookupItemSet.pm new file mode 100644 index 0000000..298bee1 --- /dev/null +++ b/C4/NCIP/LookupItemSet.pm @@ -0,0 +1,212 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::LookupItemSet; + +use Modern::Perl; + +=head1 NAME + +C4::NCIP::LookupItemSet - NCIP module for effective processing of LookupItemSet NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::LookupItemSet; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 lookupItemSet + + lookupItemSet($cgiInput) + + Expected input is as e.g. as follows: + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_item_set&bibId=95&holdQueueLengthDesired&circulationStatusDesired&itemUseRestrictionTypeDesired¬BibInfo + or + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_item_set&bibId=95 + + REQUIRED PARAMS: + Param 'service=lookup_item_set' tells svc/ncip to forward the query here. + Param 'bibId=4' specifies biblionumber look for. + + OPTIONAL PARAMS: + holdQueueLengthDesired specifies to include number of reserves placed on items of this biblio or on biblio itself + circulationStatusDesired specifies to include circulation statuses of all items of this biblio + itemUseRestrictionTypeDesired specifies to inlude item use restriction types of all items of this biblio + notBibInfo specifies to omit bibliographic information (normally returned) +=cut + +sub lookupItemSet { + my ($query) = @_; + + my $bibId = $query->param('bibId'); + + C4::NCIP::NcipUtils::print400($query, "Param bibId is undefined..") + unless $bibId; + + my $result; + + my $circStatusDesired = defined $query->param('circulationStatusDesired'); + + # Parse Items within BibRecord .. + $result->{items} = parseItems($bibId, $circStatusDesired); + + C4::NCIP::NcipUtils::print404($query, "Biblio not found..") + if scalar @{$result->{items}} == 0; + + my $holdQueueDesired = defined $query->param('holdQueueLengthDesired'); + my $itemRestrictsDesired + = defined $query->param('itemUseRestrictionTypeDesired'); + + my $count = scalar @{$result->{items}}; + + $result->{itemsCount} = $count; + + for (my $i = 0; $i < $count; ++$i) { + my $item = ${$result->{items}}[$i]; + if ($holdQueueDesired or $circStatusDesired) { + + my $holds = C4::Reserves::GetReserveCountFromItemnumber( + $item->{itemnumber}); + + if ($holdQueueDesired) { + $item->{'holdQueueLength'} = $holds; + } + if ($circStatusDesired) { + $item->{'circulationStatus'} + = C4::NCIP::NcipUtils::parseCirculationStatus($item, + $holds); + + # Delete keys not needed anymore + delete $item->{onloan}; + delete $item->{itemlost}; + delete $item->{withdrawn}; + delete $item->{damaged}; + } + } + if ($itemRestrictsDesired) { + my $restrictions + = C4::NCIP::NcipUtils::parseItemUseRestrictions($item); + unless (scalar @{$restrictions} == 0) { + $item->{'itemUseRestrictions'} = $restrictions; + } + } + delete $item->{notforloan}; + } + my $desiredSomething + = $holdQueueDesired + or $itemRestrictsDesired + or $circStatusDesired; + + $result->{bibInfo} = parseBiblio($bibId) + unless $desiredSomething and defined $query->param('notBibInfo'); + + C4::NCIP::NcipUtils::printJson($query, $result); +} + +=head2 parseBiblio + + parseBiblio($biblionumber) + + On success returns hashref with bibliodata from tables biblioitems & biblio relative to NCIP + + On failure returns string + +=cut + +sub parseBiblio { + my ($bibId) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(" + SELECT biblioitems.volume, + biblioitems.number, + biblioitems.isbn, + biblioitems.issn, + biblioitems.publicationyear, + biblioitems.publishercode, + biblioitems.pages, + biblioitems.size, + biblioitems.place, + biblioitems.agerestriction, + biblio.author, + biblio.title, + biblio.unititle, + biblio.notes, + biblio.serial + FROM biblioitems + LEFT JOIN biblio ON biblio.biblionumber = biblioitems.biblionumber + WHERE biblioitems.biblionumber = ?"); + $sth->execute($bibId); + my $data = C4::NCIP::NcipUtils::clearEmptyKeys($sth->fetchrow_hashref); + + return $data || 'SQL query failed..'; +} + +=head2 parseItems + + parseItems($biblionumber, $circulationStatusDesired) + + Returns array of items with data relative to NCIP from table items + +=cut + +sub parseItems { + my ($bibId, $circStatusDesired) = @_; + my $dbh = C4::Context->dbh; + my $query = " + SELECT itemnumber, + barcode, + homebranch, + notforloan, + itemcallnumber, + restricted, + holdingbranch, + location, + ccode, + materials, + copynumber"; + if ($circStatusDesired) { + $query .= ", + onloan, + itemlost, + withdrawn, + damaged"; + } + $query .= " + FROM items + WHERE items.biblionumber = ?"; + my $sth = $dbh->prepare($query); + $sth->execute($bibId); + my @items; + my $i = 0; + while (my $data + = C4::NCIP::NcipUtils::clearEmptyKeys($sth->fetchrow_hashref)) + { + $items[$i++] = $data; + } + + return \@items; +} + +1; diff --git a/C4/NCIP/LookupRequest.pm b/C4/NCIP/LookupRequest.pm new file mode 100644 index 0000000..ee861fc --- /dev/null +++ b/C4/NCIP/LookupRequest.pm @@ -0,0 +1,85 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::LookupRequest; + +use Modern::Perl; + +=head1 NAME + +C4::NCIP::LookupRequest - NCIP module for effective processing of LookupRequest NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::LookupRequest; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 lookupRequest + + lookupRequest($cgiInput) + + Expected input is as e.g. as follows: + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_request&userId=1&itemId=111 + or + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_request&requestId=83 + + REQUIRED PARAMS: + Param 'service=lookup_request' tells svc/ncip to forward the query here. + Either: + Param 'userId=3' specifies borrowernumber to look for. + Param 'itemId=1' specifies itemnumber to look for. + Or: + Param 'requestId=83' specifies number of request to look for- +=cut + +sub lookupRequest { + my ($query) = @_; + my $requestId = $query->param('requestId'); + + my $result; + if (defined $requestId) { + $result = C4::Reserves::GetReserve($requestId); + } else { + my $userId = $query->param('userId'); + my $itemId = $query->param('itemId'); + + C4::NCIP::NcipUtils::print400($query, + 'You have to specify \'requestId\' or both \'userId\' & \'itemId\'..' + ) unless (defined $userId and defined $itemId); + + $result + = C4::Reserves::GetReserveFromBorrowernumberAndItemnumber($userId, + $itemId); + } + + C4::NCIP::NcipUtils::print404($query, "Request not found..") + unless $result; + + C4::NCIP::NcipUtils::clearEmptyKeys($result); + + C4::NCIP::NcipUtils::printJson($query, $result); +} +1; diff --git a/C4/NCIP/LookupUser.pm b/C4/NCIP/LookupUser.pm new file mode 100644 index 0000000..73d0fc8 --- /dev/null +++ b/C4/NCIP/LookupUser.pm @@ -0,0 +1,192 @@ +#!/usr/bin/perl + +# Copyright 2013 BibLibre +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::LookupUser; + +use Modern::Perl; +use C4::NCIP::NcipUtils; + +=head1 NAME + +C4::NCIP::LookupUser - NCIP module for effective processing of LookupUser NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::LookupUser; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 lookupUser + + lookupUser($cgiInput) + + Expected input is as e.g. as follows: + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_user&userId=3&loanedItemsDesired&requestedItemsDesired&userFiscalAccountDesired¬UserInfo + or + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=lookup_user&userId=3 + + REQUIRED PARAMS: + Param 'service=lookup_user' tells svc/ncip to forward the query here. + Param 'userId=3' specifies borrowernumber to look for. + + OPTIONAL PARAMS: + loanedItemsDesired specifies to include user's loaned items + requestedItemsDesired specifies to include user's holds + userFiscalAccountDesired specifies to inlude user's transactions + notUserInfo specifies to omit looking up user's personal info as address, name etc. +=cut + +sub lookupUser { + my ($query) = @_; + my $userId = $query->param('userId'); + C4::NCIP::NcipUtils::print400($query, "Param userId is undefined..") + unless $userId; + + my $userData = parseUserData($userId); + + C4::NCIP::NcipUtils::print404($query, "User not found..") + unless $userData; + + my $results; + my $desiredSomething = 0; + if (defined $query->param('loanedItemsDesired')) { + $results->{'loanedItems'} = parseLoanedItems($userId); + $desiredSomething = 1; + } + if (defined $query->param('requestedItemsDesired')) { + my @reserves + = C4::Reserves::GetReservesFromBorrowernumber($userId, undef); + + C4::NCIP::NcipUtils::clearEmptyKeysWithinArray(@reserves); + + $results->{'requestedItems'} = \@reserves; + $desiredSomething = 1; + } + if (defined $query->param('userFiscalAccountDesired')) { + $results->{'userFiscalAccount'} = parseUserFiscalAccount($userId); + $desiredSomething = 1; + } + $results->{'userInfo'} = $userData + unless $desiredSomething and defined $query->param('notUserInfo'); + + C4::NCIP::NcipUtils::printJson($query, $results); +} + +=head2 parseUserData + + parseUserData($borrowenumber) + + Returns hashref of user's personal data as they are in table borrowers +=cut + +sub parseUserData { + my ($userId) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(" + SELECT surname, + firstname, + title, + othernames, + streetnumber, + address, + address2, + city, + state, + zipcode, + country, + email, + phone, + mobile, + fax, + emailpro, + phonepro, + B_streetnumber, + B_address, + B_address2, + B_city, + B_state, + B_zipcode, + B_country, + B_email, + B_phone, + categorycode, + dateenrolled, + dateexpiry + FROM borrowers + WHERE borrowernumber = ?"); + $sth->execute($userId); + return C4::NCIP::NcipUtils::clearEmptyKeys($sth->fetchrow_hashref); +} + +=head2 parseLoanedItems + + parseLoanedItems($borrowernumber) + + Returns array of user's issues with only these keys: issuedate, date_due, itemnumber + +=cut + +sub parseLoanedItems { + my ($userId) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(" + SELECT issuedate, + date_due, + itemnumber + FROM issues + WHERE borrowernumber = ?"); + $sth->execute($userId); + + return \@{$sth->fetchall_arrayref({})}; +} + +=head2 parseUserFiscalAccount + + parseUserFiscalAccount($borrowenumber) + + Returns array of user's accountlines with these keys: accountno, itemnumber, date, amount, description, note + +=cut + +sub parseUserFiscalAccount { + my ($userId) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(" + SELECT accountno, + itemnumber, + date, + amount, + description, + note + FROM accountlines + WHERE borrowernumber = ? + ORDER BY date desc,timestamp DESC"); + $sth->execute($userId); + + return \@{$sth->fetchall_arrayref({})}; +} + +1; + diff --git a/C4/NCIP/NcipUtils.pm b/C4/NCIP/NcipUtils.pm new file mode 100644 index 0000000..d2cb254 --- /dev/null +++ b/C4/NCIP/NcipUtils.pm @@ -0,0 +1,199 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::NcipUtils; + +use Modern::Perl; +use JSON qw(to_json); + +=head1 NAME + +C4::NCIP::NcipUtils - NCIP Common subroutines used in most of C4::NCIP modules + +=head1 SYNOPSIS + + use C4::NCIP::NcipUtils; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 clearEmptyKeys + + clearEmptyKeys($hashref) + +=cut + +sub clearEmptyKeys { + my ($hashref) = @_; + + return undef unless $hashref; + + foreach my $key (keys $hashref) { + delete $hashref->{$key} unless $hashref->{$key}; + } + return $hashref; +} + +=head2 clearEmptyKeysWithinArray + + clearEmptyKeysWithinArray($arrayWithHashrefs) + +=cut + +sub clearEmptyKeysWithinArray { + my (@arrayOfHashrefs) = @_; + + for (my $i = 0; $i < scalar @arrayOfHashrefs; ++$i) { + clearEmptyKeys($arrayOfHashrefs[$i]); + } + return \@arrayOfHashrefs; +} + +=head2 parseCirculationStatus + + parseCirculationStatus($item, $numberOfHoldsOnItem) + + Returns one of these: + On Loan + In Transit Between Library Locations + Not Available + Available On Shelf + +=cut + +sub parseCirculationStatus { + my ($item, $holds) = @_; + + if ($holds != 0 or $item->{datedue} or $item->{onloan}) { + return 'On Loan'; + } + if ($item->{transfertwhen}) { + return 'In Transit Between Library Locations'; + } + if ( $item->{notforloan_per_itemtype} + or $item->{itemlost} + or $item->{withdrawn} + or $item->{damaged}) + { + return 'Not Available'; + } + + return 'Available On Shelf'; +} + +=head2 parseItemUseRestrictions + + parseItemUseRestrictions($item) + + Returns array of restriction NCIP formatted + For now can return only 'In Library Use Only' within array if $item->{notforloan} is true + +=cut + +sub parseItemUseRestrictions { +# Possible standardized values can be found here: +# https://code.google.com/p/xcncip2toolkit/source/browse/core/trunk/service/src/main/java/org/extensiblecatalog/ncip/v2/service/Version1ItemUseRestrictionType.java + + my ($item) = @_; + + my @toReturn; + my $i = 0; + if ($item->{notforloan}) { + $toReturn[$i++] = 'In Library Use Only'; + } + return \@toReturn; +} + +=head2 printJson + + printJson($cgiInput, $hashref) + + Prints header as text/plain with charset utf-8 and status 200 & converts $hashref to json format being printed to output. + +=cut + +sub printJson { + my ($query, $string) = @_; + print $query->header( + -type => 'text/plain', + -charset => 'utf-8', + -status => '200 OK' + ), + to_json($string); + exit 0; +} + +=head2 print400 + + print400($cgiInput, $message) + +=cut + +sub print400 { + my ($query, $string) = @_; + print $query->header(-type => 'text/plain', -status => '400 Bad Request'), + $string; + exit 0; +} + +=head2 print403 + + print403($cgiInput, $message) + +=cut + +sub print403 { + my ($query, $string) = @_; + print $query->header(-type => 'text/plain', -status => '403 Forbidden'), + $string; + exit 0; +} + +=head2 print404 + + print404($cgiInput, $message) + +=cut + +sub print404 { + my ($query, $string) = @_; + print $query->header(-type => 'text/plain', -status => '404 Not Found'), + $string; + exit 0; +} + +=head2 print409 + + print409($cgiInput, $message) + +=cut + +sub print409 { + my ($query, $string) = @_; + print $query->header(-type => 'text/plain', -status => '409 Conflict'), + $string; + exit 0; +} + +1; diff --git a/C4/NCIP/RenewItem.pm b/C4/NCIP/RenewItem.pm new file mode 100644 index 0000000..634d35b --- /dev/null +++ b/C4/NCIP/RenewItem.pm @@ -0,0 +1,147 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::RenewItem; + +use Modern::Perl; + +use JSON qw(to_json); + +=head1 NAME + +C4::NCIP::RenewItem - NCIP module for effective processing of RenewItem NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::RenewItem; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 renewItem + + renewItem($cgiInput) + + Expected input is as e.g. as follows: + http://188.166.14.82:8080/cgi-bin/koha/svc/ncip?service=renew_item&desiredDateDue=20/04/2015&itemId=382&userId=3 + + REQUIRED PARAMS: + Param 'service=renew_item' tells svc/ncip to forward the query here. + Param 'userId=3' specifies borrowernumber as current borrower of Renewal item. + Param 'itemId=4' specifies itemnumber to place Renewal on. + + OPTIONAL PARAMS: + Param 'desiredDateDue=20/04/2015' specifies when would user like to have new DateDue - it is checked against Koha's default RenewalDate & if it is bigger than that, Koha's default RenewalDate is used instead +=cut + +sub renewItem { + my $query = shift; + my $itemId = $query->param('itemId'); + my $userId = $query->param('userId'); + my $branch = $query->param('branch') || C4::Context->userenv->{'branch'}; + my $biblio = C4::Biblio::GetBiblioFromItemNumber($itemId); + + unless ($itemId) { + print $query->header( + -type => 'text/plain', + -status => '400 Bad Request' + ); + print "itemId is undefined.."; + exit 0; + } + + unless ($userId) { + print $query->header( + -type => 'text/plain', + -status => '400 Bad Request' + ); + print "userId is undefined.."; + exit 0; + } + + my $dateDue = $query->param('desiredDateDue'); + if ($dateDue) { # Need to restrict maximal DateDue .. + my $dbh = C4::Context->dbh; + # Find the issues record for this book + my $sth = $dbh->prepare( + "SELECT branchcode FROM issues WHERE itemnumber = ?"); + $sth->execute($itemId); + my $issueBranchCode = $sth->fetchrow_array; + unless ($issueBranchCode) { + print $query->header( + -type => 'text/plain', + -status => '404 Not Found' + ); + print 'Checkout wasn\'t found .. Nothing to renew..'; + exit 0; + } + + my $itemtype + = (C4::Context->preference('item-level_itypes')) + ? $biblio->{'itype'} + : $biblio->{'itemtype'}; + + my $now = DateTime->now(time_zone => C4::Context->tz()); + my $borrower = C4::Members::GetMember(borrowernumber => $userId); + unless ($borrower) { + print $query->header( + -type => 'text/plain', + -status => '404 Not Found' + ); + print 'User wasn\'t found ..'; + exit 0; + } + + my $maxDateDue + = C4::Circulation::CalcDateDue($now, $itemtype, $issueBranchCode, + $borrower, 'is a renewal'); + + $dateDue = Koha::DateUtils::dt_from_string($dateDue); + $dateDue->set_hour(23); + $dateDue->set_minute(59); + if ($dateDue > $maxDateDue) { + $dateDue = $maxDateDue; + } # Here is the restriction done .. + + } + my ($okay, $error) + = C4::Circulation::CanBookBeRenewed($userId, $itemId, '0'); + + my $result; + if ($okay) { + $dateDue = C4::Circulation::AddRenewal($userId, $itemId, $branch, + $dateDue); + $result->{'dateDue'} = Koha::DateUtils::output_pref( + {dt => $dateDue, as_due_date => 1}); + } else { + $result->{'error'} = $error; + } + + print $query->header(-type => 'text/plain', -charset => 'utf-8',); + print to_json($result); + + exit 0; +} + +1; diff --git a/C4/NCIP/RequestItem.pm b/C4/NCIP/RequestItem.pm new file mode 100644 index 0000000..cd296bb --- /dev/null +++ b/C4/NCIP/RequestItem.pm @@ -0,0 +1,194 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +package C4::NCIP::RequestItem; + +use Modern::Perl; + +=head1 NAME + +C4::NCIP::RequestItem - NCIP module for effective processing of RequestItem NCIP service + +=head1 SYNOPSIS + + use C4::NCIP::RequestItem; + +=head1 DESCRIPTION + + Info about NCIP and it's services can be found here: http://www.niso.org/workrooms/ncip/resources/ + +=cut + +=head1 METHODS + +=head2 requestItem + + requestItem($cgiInput) + + Expected input is as e.g. as follows: + + http://KohaIntranet:8080/cgi-bin/koha/svc/ncip?service=request_item&requestType=Hold&userId=3&itemid=4&pickupExpiryDate=28/03/2015&pickupLocation=DOSP + or + http://KohaIntranet:8080/cgi-bin/koha/svc/ncip?service=request_item&userId=3&bibId=7 + + + REQUIRED PARAMS: + Param 'service=request_item' tells svc/ncip to forward the query here. + Param 'userId=3' specifies borrowernumber to place Reserve to. + Param 'itemId=4' specifies itemnumber to place Reserve on. + This param can be replaced with 'barcode=1103246'. But still one of these is required. + Or with 'bibId=3' - then it is Bibliographic Level Hold. + + OPTIONAL PARAMS: + Param 'requestType=Hold' can be either 'Hold' or 'Loan'. + Param 'pickupExpiryDate=28/06/2015' tells until what date is user interested into specified item. + Param 'pickuplocation=DOSP' specifies which branch is user expecting pickup at. + +=cut + +sub requestItem { + my $query = shift; + my $userId = $query->param('userId'); + + C4::NCIP::NcipUtils::print400($query, "Param userId is undefined..") + unless $userId; + + my $bibId = $query->param('bibId'); + my $itemId = $query->param('itemId'); + my $barcode = $query->param('barcode'); + + C4::NCIP::NcipUtils::print400($query, + "Cannot process both bibId & itemId/barcode .. you have to choose only one" + ) if $bibId and ($itemId or $barcode); + + my $itemLevelHold = 1; + unless ($itemId) { + if ($bibId) { + my $canBeReserved + = C4::Reserves::CanBookBeReserved($userId, $bibId); + + print409($query, "Book cannot be reserved.. $canBeReserved") + unless ($canBeReserved eq 'OK'); + + $itemLevelHold = 0; + } else { + C4::NCIP::NcipUtils::print400($query, + "Param bibId neither any of itemId and barcode is undefined") + unless $barcode; + + $itemId = C4::Items::GetItemnumberFromBarcode($barcode); + } + } + + if ($itemLevelHold) { + my $canBeReserved = C4::Reserves::CanItemBeReserved($userId, $itemId); + + C4::NCIP::NcipUtils::print409($query, + "Item cannot be reserved.. $canBeReserved") + unless $canBeReserved eq 'OK'; + + $bibId = C4::Biblio::GetBiblionumberFromItemnumber($itemId); + } + +# RequestType specifies if user wants the book now or doesn't mind to get into queue + my $requestType = $query->param('requestType'); + + if ($requestType) { + C4::NCIP::NcipUtils::print400($query, + "Param requestType not recognized.. Can be \'Loan\' or \'Hold\'") + if (not $requestType =~ /^Loan$|^Hold$/); + } else { + $requestType = 'Hold'; + } + + # Process rank & whether user hasn't requested this item yet .. + my $reserves = C4::Reserves::GetReservesFromBiblionumber( + {biblionumber => $bibId, itemnumber => $itemId, all_dates => 1}); + + foreach my $res (@$reserves) { + C4::NCIP::NcipUtils::print403($query, + "User already has item requested") + if $res->{borrowernumber} eq $userId; + } + + my $rank = scalar(@$reserves); + + C4::NCIP::NcipUtils::print409($query, + "Loan not possible .. holdqueuelength exists") + if $requestType ne 'Hold' and $rank != 0; + + my $expirationdate = $query->param('pickupExpiryDate'); + my $startdate = $query->param('earliestDateNeeded'); + my $notes = $query->param('notes') || 'Placed by svc/ncip'; + my $pickupLocation = $query->param('pickupLocation') + || C4::Context->userenv->{'branch'}; + + if ($itemLevelHold) { + placeHold( + $query, $bibId, $itemId, $userId, + $pickupLocation, $startdate, $expirationdate, $notes, + ++$rank, undef + ); + } else { + placeHold( + $query, $bibId, undef, $userId, + $pickupLocation, $startdate, $expirationdate, $notes, + ++$rank, 'any' + ); + } +} + +=head2 placeHold + + placeHold($inputCGI, $biblionumber, $itemnumber, $borrowernumber, $pickup, $startdate, $expirationdate, $notes, $rank, $requesttype) + +=cut + +sub placeHold { + my ($query, $bibId, $itemId, $userId, + $branch, $startdate, $expirationdate, $notes, + $rank, $request + ) = @_; + + my $found; + + my $userExists = C4::Members::GetBorrowerCategorycode($userId); + + C4::NCIP::NcipUtils::print404($query, "User not found..") + unless $userExists; + + my $reserveId = C4::Reserves::AddReserve( + $branch, $userId, $bibId, 'a', + undef, $rank, $startdate, $expirationdate, + $notes, undef, $itemId, $found + ); + + my $results; + + $results->{'status'} = 'reserved'; + $results->{'bibId'} = $bibId; + $results->{'userId'} = $userId; + $results->{'requestId'} = $reserveId; + + $results->{'itemId'} = $itemId if $itemId; + + C4::NCIP::NcipUtils::printJson($query, $results); +} + +1; diff --git a/C4/Reserves.pm b/C4/Reserves.pm index b82387f..48cf73c 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -100,9 +100,11 @@ BEGIN { &GetReservesFromItemnumber &GetReservesFromBiblionumber &GetReservesFromBorrowernumber + &GetReserveFromBorrowernumberAndItemnumber &GetReservesForBranch &GetReservesToBranch &GetReserveCount + &GetReserveCountFromItemnumber &GetReserveFee &GetReserveInfo &GetReserveStatus @@ -241,7 +243,7 @@ sub AddReserve { } #} - ($const eq "o" || $const eq "e") or return; # FIXME: why not have a useful return value? + ($const eq "o" || $const eq "e") or return $reserve_id; $query = qq{ INSERT INTO reserveconstraints (borrowernumber,biblionumber,reservedate,biblioitemnumber) @@ -450,6 +452,31 @@ sub GetReservesFromBorrowernumber { my $data = $sth->fetchall_arrayref({}); return @$data; } + +=head2 GetReserveFromBorrowernumberAndItemnumber + + $reserve = GetReserveFromBorrowernumberAndItemnumber($borrowernumber, $itemnumber); + +Returns matching reserve of borrower on an item specified. + +=cut + +sub GetReserveFromBorrowernumberAndItemnumber { + my ($borrowernumber, $itemnumber) = @_; + my $dbh = C4::Context->dbh; + my $sth; + $sth = $dbh->prepare(" + SELECT * + FROM reserves + WHERE borrowernumber=? + AND itemnumber =? + "); + $sth->execute($borrowernumber, $itemnumber); + + return ${$sth->fetchall_arrayref({})}[0]; + +} + #------------------------------------------------------------------------------------- =head2 CanBookBeReserved @@ -640,6 +667,30 @@ sub GetReserveCount { return $row->{counter}; } +=head2 GetReserveCountFromItemnumber + + $number = &GetReserveCountFromItemnumber($itemnumber); + +this function returns the number of reservation for an itemnumber given on input arg. + +=cut + + +sub GetReserveCountFromItemnumber { + my ($itemnumber) = @_; + + my $dbh = C4::Context->dbh; + + my $sth = $dbh->prepare(" + SELECT COUNT(*) AS counter + FROM reserves + WHERE itemnumber = ?"); + + $sth->execute($itemnumber); + + return $sth->fetchrow_hashref->{counter}; +} + =head2 GetOtherReserves ($messages,$nextreservinfo)=$GetOtherReserves(itemnumber); diff --git a/svc/ncip b/svc/ncip new file mode 100755 index 0000000..575ddae --- /dev/null +++ b/svc/ncip @@ -0,0 +1,79 @@ +#!/usr/bin/perl + +# Copyright 2007 LibLime +# Copyright 2012 software.coop and MJ Ray +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +use strict; +use warnings; + +use CGI qw ( -utf8 ); +use C4::Auth qw/check_api_auth/; + +use C4::NCIP::LookupItem qw/lookupItem/; +use C4::NCIP::LookupItemSet qw/lookupItemSet/; +use C4::NCIP::LookupUser qw/lookupUser/; +use C4::NCIP::LookupRequest qw/lookupRequest/; +use C4::NCIP::RequestItem qw/requestItem/; +use C4::NCIP::RenewItem qw/renewItem/; +use C4::NCIP::CancelRequestItem qw/cancelRequestItem/; + +my $query = new CGI; +binmode STDOUT, ':encoding(UTF-8)'; + +my ($status, undef, undef) + = check_api_auth($query, {editcatalogue => 'edit_catalogue'}); + +C4::NCIP::NcipUtils::print403($query, $status) + unless ($status eq "ok"); + +# do initial validation + +if ($query->request_method eq "GET") { + my $service = $query->param('service'); + + C4::NCIP::NcipUtils::print400($query, "Param service is undefined..") + unless $service; + + if ($service eq 'lookup_item') { + C4::NCIP::LookupItem::lookupItem($query); + } elsif ($service eq 'lookup_item_set') { + C4::NCIP::LookupItemSet::lookupItemSet($query); + } elsif ($service eq 'lookup_user') { + C4::NCIP::LookupUser::lookupUser($query); + } elsif ($service eq 'lookup_request') { + C4::NCIP::LookupRequest::lookupRequest($query); + } elsif ($service eq 'request_item') { + C4::NCIP::RequestItem::requestItem($query); + } elsif ($service eq 'renew_item') { + C4::NCIP::RenewItem::renewItem($query); + } elsif ($service eq 'cancel_request_item') { + C4::NCIP::CancelRequestItem::cancelRequestItem($query); + } else { + C4::NCIP::NcipUtils::print400($query, + "Param service not recognized.."); + } +} else { + print $query->header( + -type => 'text/plain', + -status => '405 Method Not Allowed' + ), + 'Only GET method is allowed..'; + exit 0; +} + -- 1.7.10.4