Bug 19618: Add api endpoint for club holds
[koha.git] / Koha / REST / V1 / Checkouts.pm
1 package Koha::REST::V1::Checkouts;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 3 of the License, or (at your option) any later
8 # version.
9 #
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with Koha; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 use Modern::Perl;
19
20 use Mojo::Base 'Mojolicious::Controller';
21 use Mojo::JSON;
22
23 use C4::Auth qw( haspermission );
24 use C4::Context;
25 use C4::Circulation;
26 use Koha::Checkouts;
27 use Koha::IssuingRules;
28
29 use Try::Tiny;
30
31 =head1 NAME
32
33 Koha::REST::V1::Checkout
34
35 =head1 API
36
37 =head2 Methods
38
39 =head3 list
40
41 List Koha::Checkout objects
42
43 =cut
44
45 sub list {
46     my $c = shift->openapi->valid_input or return;
47     try {
48         my $checkouts_set = Koha::Checkouts->new;
49         my $checkouts = $c->objects->search( $checkouts_set, \&_to_model, \&_to_api );
50         return $c->render( status => 200, openapi => $checkouts );
51     } catch {
52         if ( $_->isa('DBIx::Class::Exception') ) {
53             return $c->render(
54                 status => 500,
55                 openapi => { error => $_->{msg} }
56             );
57         } else {
58             return $c->render(
59                 status => 500,
60                 openapi => { error => "Something went wrong, check the logs." }
61             );
62         }
63     };
64 }
65
66 =head3 get
67
68 get one checkout
69
70 =cut
71
72 sub get {
73     my $c = shift->openapi->valid_input or return;
74
75     my $checkout = Koha::Checkouts->find( $c->validation->param('checkout_id') );
76
77     unless ($checkout) {
78         return $c->render(
79             status => 404,
80             openapi => { error => "Checkout doesn't exist" }
81         );
82     }
83
84     return $c->render(
85         status => 200,
86         openapi => _to_api($checkout->TO_JSON)
87     );
88 }
89
90 =head3 renew
91
92 Renew a checkout
93
94 =cut
95
96 sub renew {
97     my $c = shift->openapi->valid_input or return;
98
99     my $checkout_id = $c->validation->param('checkout_id');
100     my $checkout = Koha::Checkouts->find( $checkout_id );
101
102     unless ($checkout) {
103         return $c->render(
104             status => 404,
105             openapi => { error => "Checkout doesn't exist" }
106         );
107     }
108
109     my $borrowernumber = $checkout->borrowernumber;
110     my $itemnumber = $checkout->itemnumber;
111
112     my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
113         $borrowernumber, $itemnumber);
114
115     if (!$can_renew) {
116         return $c->render(
117             status => 403,
118             openapi => { error => "Renewal not authorized ($error)" }
119         );
120     }
121
122     AddRenewal($borrowernumber, $itemnumber, $checkout->branchcode);
123     $checkout = Koha::Checkouts->find($checkout_id);
124
125     $c->res->headers->location( $c->req->url->to_string );
126     return $c->render(
127         status => 201,
128         openapi => _to_api( $checkout->TO_JSON )
129     );
130 }
131
132 =head3 allows_renewal
133
134 Checks if the checkout could be renewed and return the related information.
135
136 =cut
137
138 sub allows_renewal {
139     my $c = shift->openapi->valid_input or return;
140
141     my $checkout_id = $c->validation->param('checkout_id');
142     my $checkout = Koha::Checkouts->find( $checkout_id );
143
144     unless ($checkout) {
145         return $c->render(
146             status => 404,
147             openapi => { error => "Checkout doesn't exist" }
148         );
149     }
150
151     my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
152         $checkout->borrowernumber, $checkout->itemnumber);
153
154     my $renewable = Mojo::JSON->false;
155     $renewable = Mojo::JSON->true if $can_renew;
156
157     my $rule = Koha::IssuingRules->get_effective_issuing_rule(
158         {
159             categorycode => $checkout->patron->categorycode,
160             itemtype     => $checkout->item->effective_itemtype,
161             branchcode   => $checkout->branchcode,
162         }
163     );
164     return $c->render(
165         status => 200,
166         openapi => {
167             allows_renewal => $renewable,
168             max_renewals => $rule->renewalsallowed,
169             current_renewals => $checkout->renewals,
170             error => $error
171         }
172     );
173 }
174
175 =head3 _to_api
176
177 Helper function that maps a hashref of Koha::Checkout attributes into REST api
178 attribute names.
179
180 =cut
181
182 sub _to_api {
183     my $checkout = shift;
184
185     foreach my $column ( keys %{ $Koha::REST::V1::Checkouts::to_api_mapping } ) {
186         my $mapped_column = $Koha::REST::V1::Checkouts::to_api_mapping->{$column};
187         if ( exists $checkout->{ $column } && defined $mapped_column )
188         {
189             $checkout->{ $mapped_column } = delete $checkout->{ $column };
190         }
191         elsif ( exists $checkout->{ $column } && !defined $mapped_column ) {
192             delete $checkout->{ $column };
193         }
194     }
195     return $checkout;
196 }
197
198 =head3 _to_model
199
200 Helper function that maps REST api objects into Koha::Checkouts
201 attribute names.
202
203 =cut
204
205 sub _to_model {
206     my $checkout = shift;
207
208     foreach my $attribute ( keys %{ $Koha::REST::V1::Checkouts::to_model_mapping } ) {
209         my $mapped_attribute = $Koha::REST::V1::Checkouts::to_model_mapping->{$attribute};
210         if ( exists $checkout->{ $attribute } && defined $mapped_attribute )
211         {
212             $checkout->{ $mapped_attribute } = delete $checkout->{ $attribute };
213         }
214         elsif ( exists $checkout->{ $attribute } && !defined $mapped_attribute )
215         {
216             delete $checkout->{ $attribute };
217         }
218     }
219     return $checkout;
220 }
221
222 =head2 Global variables
223
224 =head3 $to_api_mapping
225
226 =cut
227
228 our $to_api_mapping = {
229     issue_id        => 'checkout_id',
230     borrowernumber  => 'patron_id',
231     itemnumber      => 'item_id',
232     date_due        => 'due_date',
233     branchcode      => 'library_id',
234     returndate      => 'checkin_date',
235     lastreneweddate => 'last_renewed_date',
236     issuedate       => 'checkout_date',
237     notedate        => 'note_date',
238 };
239
240 =head3 $to_model_mapping
241
242 =cut
243
244 our $to_model_mapping = {
245     checkout_id       => 'issue_id',
246     patron_id         => 'borrowernumber',
247     item_id           => 'itemnumber',
248     due_date          => 'date_due',
249     library_id        => 'branchcode',
250     checkin_date      => 'returndate',
251     last_renewed_date => 'lastreneweddate',
252     checkout_date     => 'issuedate',
253     note_date         => 'notedate',
254 };
255
256 1;