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 332-337 Link Here
332
          }
332
          }
333
        }
333
        }
334
      }
334
      }
335
    },
336
    "/checkouts": {
337
      "get": {
338
        "operationId": "listCheckouts",
339
        "tags": ["borrowers", "checkouts"],
340
        "parameters": [
341
          {
342
            "name": "borrowernumber",
343
            "in": "query",
344
            "description": "Internal patron identifier",
345
            "required": false,
346
            "type": "integer"
347
          }
348
        ],
349
        "produces": [
350
          "application/json"
351
        ],
352
        "responses": {
353
          "200": {
354
            "description": "A list of checkouts",
355
            "schema": {
356
              "$ref": "#/definitions/checkouts"
357
            }
358
          },
359
          "403": {
360
            "description": "Access forbidden",
361
            "schema": { "$ref": "#/definitions/error" }
362
          },
363
          "404": {
364
            "description": "Borrower not found",
365
            "schema": {
366
              "$ref": "#/definitions/error"
367
            }
368
          }
369
        }
370
      }
371
    },
372
    "/checkouts/{checkout_id}": {
373
      "get": {
374
        "operationId": "getCheckout",
375
        "tags": ["borrowers", "checkouts"],
376
        "parameters": [
377
          {
378
            "name": "checkout_id",
379
            "in": "path",
380
            "description": "Internal checkout identifier",
381
            "required": true,
382
            "type": "integer"
383
          }
384
        ],
385
        "produces": ["application/json"],
386
        "responses": {
387
          "200": {
388
            "description": "Updated borrower's checkout",
389
            "schema": { "$ref": "#/definitions/checkout" }
390
          },
391
          "403": {
392
            "description": "Access forbidden",
393
            "schema": { "$ref": "#/definitions/error" }
394
          },
395
          "404": {
396
            "description": "Checkout not found",
397
            "schema": { "$ref": "#/definitions/error" }
398
          }
399
        }
400
      },
401
      "put": {
402
        "operationId": "renewCheckout",
403
        "tags": ["borrowers", "checkouts"],
404
        "parameters": [
405
          {
406
            "name": "checkout_id",
407
            "in": "path",
408
            "description": "Internal checkout identifier",
409
            "required": true,
410
            "type": "integer"
411
          }
412
        ],
413
        "produces": ["application/json"],
414
        "responses": {
415
          "200": {
416
            "description": "Updated borrower's checkout",
417
            "schema": { "$ref": "#/definitions/checkout" }
418
          },
419
          "403": {
420
            "description": "Cannot renew checkout",
421
            "schema": { "$ref": "#/definitions/error" }
422
          },
423
          "404": {
424
            "description": "Checkout not found",
425
            "schema": { "$ref": "#/definitions/error" }
426
          }
427
        }
428
      }
335
    }
429
    }
336
  },
430
  },
337
  "definitions": {
431
  "definitions": {
(-)a/t/db_dependent/api/v1/checkouts.t (-1 / +159 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
}

Return to bug 13895