View | Details | Raw Unified | Return to bug 13895
Collapse All | Expand All

(-)a/Koha/REST/V1/Checkout.pm (+94 lines)
Line 0 Link Here
1
package Koha::REST::V1::Checkout;
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
22
use C4::Auth qw( haspermission );
23
use C4::Circulation;
24
use Koha::Issues;
25
26
sub list {
27
    my ($c, $args, $cb) = @_;
28
29
    my $user = $c->stash('koha.user');
30
    unless ($user && haspermission($user->userid, { circulate => "circulate_remaining_permissions" })) {
31
        return $c->$cb({error => "You don't have the required permission"}, 403);
32
    }
33
34
    my $borrowernumber = $c->param('borrowernumber');
35
    my $checkouts = C4::Circulation::GetIssues({
36
        borrowernumber => $borrowernumber
37
    });
38
39
    $c->$cb($checkouts, 200);
40
}
41
42
sub get {
43
    my ($c, $args, $cb) = @_;
44
45
    my $user = $c->stash('koha.user');
46
    unless ($user && haspermission($user->userid, { circulate => "circulate_remaining_permissions" })) {
47
        return $c->$cb({error => "You don't have the required permission"}, 403);
48
    }
49
50
    my $checkout_id = $args->{checkout_id};
51
    my $checkout = Koha::Issues->find($checkout_id);
52
53
    if (!$checkout) {
54
        return $c->$cb({
55
            error => "Checkout doesn't exist"
56
        }, 404);
57
    }
58
59
    return $c->$cb($checkout->unblessed, 200);
60
}
61
62
sub renew {
63
    my ($c, $args, $cb) = @_;
64
65
    my $user = $c->stash('koha.user');
66
    unless ($user && haspermission($user->userid, { circulate => "circulate_remaining_permissions" })) {
67
        return $c->$cb({error => "You don't have the required permission"}, 403);
68
    }
69
70
    my $checkout_id = $args->{checkout_id};
71
    my $checkout = Koha::Issues->find($checkout_id);
72
73
    if (!$checkout) {
74
        return $c->$cb({
75
            error => "Checkout doesn't exists"
76
        }, 404);
77
    }
78
79
    $checkout = $checkout->unblessed;
80
    my ($borrowernumber, $itemnumber) = @$checkout{qw(borrowernumber itemnumber)};
81
    my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
82
        $borrowernumber, $itemnumber);
83
84
    if (!$can_renew) {
85
        return $c->$cb({error => "Renewal not authorized ($error)"}, 403);
86
    }
87
88
    AddRenewal($borrowernumber, $itemnumber, $checkout->{branchcode});
89
    $checkout = Koha::Issues->find($checkout_id);
90
91
    return $c->$cb($checkout->unblessed, 200);
92
}
93
94
1;
(-)a/api/v1/definitions/checkout.json (+51 lines)
Line 0 Link Here
1
{
2
    "type": "object",
3
    "properties": {
4
        "issue_id": {
5
          "type": "string",
6
          "description": "internally assigned checkout identifier"
7
        },
8
        "borrowernumber": {
9
            "type": "string",
10
            "description": "internally assigned user identifier"
11
        },
12
        "itemnumber": {
13
            "type": "string",
14
            "description": "internally assigned item identifier"
15
        },
16
        "date_due": {
17
            "description": "Due date"
18
        },
19
        "branchcode": {
20
            "type": ["string", "null"],
21
            "description": "code of patron's home branch"
22
        },
23
        "issuingbranch": {
24
            "description": "Code of the branch where issue was made"
25
        },
26
        "returndate": {
27
            "description": "Date the item was returned"
28
        },
29
        "lastreneweddate": {
30
            "description": "Date the item was last renewed"
31
        },
32
        "return": {
33
            "description": "?"
34
        },
35
        "renewals": {
36
            "description": "Number of renewals"
37
        },
38
        "auto_renew": {
39
            "description": "Auto renewal"
40
        },
41
        "timestamp": {
42
            "description": "Last update time"
43
        },
44
        "issuedate": {
45
            "description": "Date the item was issued"
46
        },
47
        "onsite_checkout": {
48
            "description": "On site checkout"
49
        }
50
    }
51
}
(-)a/api/v1/definitions/checkouts.json (+6 lines)
Line 0 Link Here
1
{
2
    "type": "array",
3
    "items": {
4
        "$ref": "./checkout.json"
5
    }
6
}
(-)a/api/v1/definitions/index.json (+2 lines)
Lines 1-5 Link Here
1
{
1
{
2
    "patron": { "$ref": "patron.json" },
2
    "patron": { "$ref": "patron.json" },
3
    "checkouts": { "$ref": "checkouts.json" },
4
    "checkout": { "$ref": "checkout.json" },
3
    "holds": { "$ref": "holds.json" },
5
    "holds": { "$ref": "holds.json" },
4
    "hold": { "$ref": "hold.json" },
6
    "hold": { "$ref": "hold.json" },
5
    "error": { "$ref": "error.json" }
7
    "error": { "$ref": "error.json" }
(-)a/api/v1/swagger.json (+94 lines)
Lines 231-236 Link Here
231
          }
231
          }
232
        }
232
        }
233
      }
233
      }
234
    },
235
    "/checkouts": {
236
      "get": {
237
        "operationId": "listCheckouts",
238
        "tags": ["borrowers", "checkouts"],
239
        "parameters": [
240
          {
241
            "name": "borrowernumber",
242
            "in": "query",
243
            "description": "Internal patron identifier",
244
            "required": false,
245
            "type": "integer"
246
          }
247
        ],
248
        "produces": [
249
          "application/json"
250
        ],
251
        "responses": {
252
          "200": {
253
            "description": "A list of checkouts",
254
            "schema": {
255
              "$ref": "#/definitions/checkouts"
256
            }
257
          },
258
          "403": {
259
            "description": "Access forbidden",
260
            "schema": { "$ref": "#/definitions/error" }
261
          },
262
          "404": {
263
            "description": "Borrower not found",
264
            "schema": {
265
              "$ref": "#/definitions/error"
266
            }
267
          }
268
        }
269
      }
270
    },
271
    "/checkouts/{checkout_id}": {
272
      "get": {
273
        "operationId": "getCheckout",
274
        "tags": ["borrowers", "checkouts"],
275
        "parameters": [
276
          {
277
            "name": "checkout_id",
278
            "in": "path",
279
            "description": "Internal checkout identifier",
280
            "required": true,
281
            "type": "integer"
282
          }
283
        ],
284
        "produces": ["application/json"],
285
        "responses": {
286
          "200": {
287
            "description": "Updated borrower's checkout",
288
            "schema": { "$ref": "#/definitions/checkout" }
289
          },
290
          "403": {
291
            "description": "Access forbidden",
292
            "schema": { "$ref": "#/definitions/error" }
293
          },
294
          "404": {
295
            "description": "Checkout not found",
296
            "schema": { "$ref": "#/definitions/error" }
297
          }
298
        }
299
      },
300
      "put": {
301
        "operationId": "renewCheckout",
302
        "tags": ["borrowers", "checkouts"],
303
        "parameters": [
304
          {
305
            "name": "checkout_id",
306
            "in": "path",
307
            "description": "Internal checkout identifier",
308
            "required": true,
309
            "type": "integer"
310
          }
311
        ],
312
        "produces": ["application/json"],
313
        "responses": {
314
          "200": {
315
            "description": "Updated borrower's checkout",
316
            "schema": { "$ref": "#/definitions/checkout" }
317
          },
318
          "403": {
319
            "description": "Cannot renew checkout",
320
            "schema": { "$ref": "#/definitions/error" }
321
          },
322
          "404": {
323
            "description": "Checkout not found",
324
            "schema": { "$ref": "#/definitions/error" }
325
          }
326
        }
327
      }
234
    }
328
    }
235
  },
329
  },
236
  "definitions": {
330
  "definitions": {
(-)a/t/db_dependent/api/v1/checkouts.t (-1 / +160 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
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 Test::More tests => 27;
21
use Test::MockModule;
22
use Test::Mojo;
23
use t::lib::TestBuilder;
24
25
use DateTime;
26
use MARC::Record;
27
28
use C4::Context;
29
use C4::Biblio;
30
use C4::Circulation;
31
use C4::Items;
32
33
use Koha::Database;
34
use Koha::Patron;
35
36
my $schema = Koha::Database->schema;
37
$schema->storage->txn_begin;
38
my $dbh = C4::Context->dbh;
39
my $builder = t::lib::TestBuilder->new;
40
$dbh->{RaiseError} = 1;
41
42
$ENV{REMOTE_ADDR} = '127.0.0.1';
43
my $t = Test::Mojo->new('Koha::REST::V1');
44
45
$dbh->do('DELETE FROM issues');
46
$dbh->do('DELETE FROM items');
47
$dbh->do('DELETE FROM issuingrules');
48
my $loggedinuser = $builder->build({ source => 'Borrower' });
49
50
$dbh->do(q{
51
    INSERT INTO user_permissions (borrowernumber, module_bit, code)
52
    VALUES (?, 1, 'circulate_remaining_permissions')
53
}, undef, $loggedinuser->{borrowernumber});
54
55
my $session = C4::Auth::get_session('');
56
$session->param('number', $loggedinuser->{ borrowernumber });
57
$session->param('id', $loggedinuser->{ userid });
58
$session->param('ip', '127.0.0.1');
59
$session->param('lasttime', time());
60
$session->flush;
61
62
my $borrower = $builder->build({ source => 'Borrower' });
63
my $borrowernumber = $borrower->{borrowernumber};
64
65
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
66
my $module = new Test::MockModule('C4::Context');
67
$module->mock('userenv', sub { { branch => $branchcode } });
68
69
my $tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$borrowernumber");
70
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
71
$t->request_ok($tx)
72
  ->status_is(200)
73
  ->json_is([]);
74
75
my $notexisting_borrowernumber = $borrowernumber + 1;
76
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$notexisting_borrowernumber");
77
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
78
$t->request_ok($tx)
79
  ->status_is(200)
80
  ->json_is([]);
81
82
my $biblionumber = create_biblio('RESTful Web APIs');
83
my $itemnumber1 = create_item($biblionumber, 'TEST000001');
84
my $itemnumber2 = create_item($biblionumber, 'TEST000002');
85
86
my $date_due = DateTime->now->add(weeks => 2);
87
my $issue1 = C4::Circulation::AddIssue($borrower, 'TEST000001', $date_due);
88
my $date_due1 = Koha::DateUtils::dt_from_string( $issue1->date_due );
89
my $issue2 = C4::Circulation::AddIssue($borrower, 'TEST000002', $date_due);
90
my $date_due2 = Koha::DateUtils::dt_from_string( $issue2->date_due );
91
92
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$borrowernumber");
93
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
94
$t->request_ok($tx)
95
  ->status_is(200)
96
  ->json_is('/0/borrowernumber' => $borrowernumber)
97
  ->json_is('/0/itemnumber' => $itemnumber1)
98
  ->json_is('/0/date_due' => $date_due1->ymd . ' ' . $date_due1->hms)
99
  ->json_is('/1/borrowernumber' => $borrowernumber)
100
  ->json_is('/1/itemnumber' => $itemnumber2)
101
  ->json_is('/1/date_due' => $date_due2->ymd . ' ' . $date_due2->hms)
102
  ->json_hasnt('/2');
103
104
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue1->issue_id);
105
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
106
$t->request_ok($tx)
107
  ->status_is(200)
108
  ->json_is('/date_due' => $date_due1->ymd . ' ' . $date_due1->hms);
109
110
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue2->issue_id);
111
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
112
$t->request_ok($tx)
113
  ->status_is(200)
114
  ->json_is('/date_due' => $date_due2->ymd . ' ' . $date_due2->hms);
115
116
117
$dbh->do('DELETE FROM issuingrules');
118
$dbh->do(q{
119
    INSERT INTO issuingrules (categorycode, branchcode, itemtype, renewalperiod, renewalsallowed)
120
    VALUES (?, ?, ?, ?, ?)
121
}, {}, '*', '*', '*', 7, 1);
122
123
my $expected_datedue = DateTime->now->add(days => 14)->set(hour => 23, minute => 59, second => 0);
124
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue1->issue_id);
125
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
126
$t->request_ok($tx)
127
  ->status_is(200)
128
  ->json_is('/date_due' => $expected_datedue->ymd . ' ' . $expected_datedue->hms);
129
130
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue1->issue_id);
131
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
132
$t->request_ok($tx)
133
  ->status_is(403)
134
  ->json_is({ error => 'Renewal not authorized (too_many)' });
135
136
sub create_biblio {
137
    my ($title) = @_;
138
139
    my $record = new MARC::Record;
140
    $record->append_fields(
141
        new MARC::Field('200', ' ', ' ', a => $title),
142
    );
143
144
    my ($biblionumber) = C4::Biblio::AddBiblio($record, '');
145
146
    return $biblionumber;
147
}
148
149
sub create_item {
150
    my ($biblionumber, $barcode) = @_;
151
152
    my $item = {
153
        barcode => $barcode,
154
    };
155
156
    my $itemnumber = C4::Items::AddItem($item, $biblionumber);
157
158
    return $itemnumber;
159
}
160

Return to bug 13895