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

(-)a/Koha/REST/V1/Checkout.pm (-9 / +56 lines)
Lines 19-25 use Modern::Perl; Link Here
19
19
20
use Mojo::Base 'Mojolicious::Controller';
20
use Mojo::Base 'Mojolicious::Controller';
21
use Mojo::JSON;
21
use Mojo::JSON;
22
23
use C4::Auth qw( haspermission );
22
use C4::Auth qw( haspermission );
24
use C4::Context;
23
use C4::Context;
25
use C4::Circulation;
24
use C4::Circulation;
Lines 105-118 sub renewability { Link Here
105
    my $borrowernumber = $checkout->borrowernumber;
104
    my $borrowernumber = $checkout->borrowernumber;
106
    my $itemnumber = $checkout->itemnumber;
105
    my $itemnumber = $checkout->itemnumber;
107
106
108
    my $OpacRenewalAllowed;
107
    unless (_opac_renewal_allowed($user, $borrowernumber))  {
109
    if ($user->borrowernumber == $borrowernumber) {
108
        return $c->render(status => 403, openapi => {
110
        $OpacRenewalAllowed = C4::Context->preference('OpacRenewalAllowed');
109
            error => "You don't have the required permission"});
111
    }
112
113
    unless ($user && ($OpacRenewalAllowed
114
            || haspermission($user->userid, { circulate => "circulate_remaining_permissions" }))) {
115
        return $c->render(status => 403, openapi => {error => "You don't have the required permission"});
116
    }
110
    }
117
111
118
    my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
112
    my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
Lines 160-163 sub gethistory { Link Here
160
    return $c->render( status => 200, openapi => $checkout );
154
    return $c->render( status => 200, openapi => $checkout );
161
}
155
}
162
156
157
sub expanded {
158
    my $c = shift->openapi->valid_input or return;
159
160
    my $borrowernumber = $c->validation->param('borrowernumber');
161
    my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber )
162
      or return;
163
    my $user = $c->stash('koha.user');
164
    my $opac_renewability = _opac_renewal_allowed($user, $borrowernumber);
165
    my $checkouts = Koha::Checkouts->search({
166
        borrowernumber => $borrowernumber
167
    });
168
    my $checkouts_json = $checkouts->TO_JSON;
169
170
    foreach my $checkout (@{$checkouts_json}) {
171
        my $item         = Koha::Items->find($checkout->{itemnumber});
172
        my $branchcode   = C4::Circulation::_GetCircControlBranch( $item->unblessed,
173
                                                                   $borrower);
174
        my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
175
            {   categorycode => $borrower->{categorycode},
176
                itemtype     => $item->effective_itemtype,
177
                branchcode   => $branchcode
178
            }
179
        );
180
        $checkout->{'max_renewals'} = $issuing_rule
181
                        ? 0+$issuing_rule->renewalsallowed : 0;
182
        my ($can_renew, $error);
183
        if ($opac_renewability) {
184
            ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
185
            $borrowernumber, $checkout->{'itemnumber'});
186
        }
187
188
        $checkout->{'renewable'} = $can_renew
189
        ? Mojo::JSON->true : Mojo::JSON->false;
190
    }
191
192
    return $c->render( status => 200, openapi => $checkouts_json );
193
}
194
195
sub _opac_renewal_allowed {
196
    my ($user, $borrowernumber) = @_;
197
198
    my $OpacRenewalAllowed;
199
    if ($user->borrowernumber == $borrowernumber) {
200
        $OpacRenewalAllowed = C4::Context->preference('OpacRenewalAllowed');
201
    }
202
203
    unless ($user && ($OpacRenewalAllowed || haspermission($user->userid,
204
                           { circulate => "circulate_remaining_permissions" }))) {
205
        return 0;
206
    }
207
    return 1;
208
}
209
163
1;
210
1;
(-)a/api/v1/swagger/definitions.json (+3 lines)
Lines 32-37 Link Here
32
  "checkout": {
32
  "checkout": {
33
    "$ref": "definitions/checkout.json"
33
    "$ref": "definitions/checkout.json"
34
  },
34
  },
35
  "checkoutexpanded": {
36
    "$ref": "definitions/checkoutexpanded.json"
37
  },
35
  "holds": {
38
  "holds": {
36
    "$ref": "definitions/holds.json"
39
    "$ref": "definitions/holds.json"
37
  },
40
  },
(-)a/api/v1/swagger/definitions/checkoutexpanded.json (+16 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "allOf": [
4
    { "$ref": "checkout.json" }
5
  ],
6
  "properties": {
7
    "renewability": {
8
      "type": "boolean",
9
      "description": "renewability status"
10
    },
11
    "max_renewals": {
12
      "type": "integer",
13
      "description": "maximum number of renewals allowed"
14
    }
15
  }
16
}
(-)a/api/v1/swagger/paths.json (+3 lines)
Lines 59-64 Link Here
59
  "/checkouts/{checkout_id}/renewability": {
59
  "/checkouts/{checkout_id}/renewability": {
60
    "$ref": "paths/checkouts.json#/~1checkouts~1{checkout_id}~1renewability"
60
    "$ref": "paths/checkouts.json#/~1checkouts~1{checkout_id}~1renewability"
61
  },
61
  },
62
  "/checkouts/expanded": {
63
    "$ref": "paths/checkouts.json#/~1checkouts~1expanded"
64
  },
62
  "/checkouts/history": {
65
  "/checkouts/history": {
63
    "$ref": "paths/checkouts.json#/~1checkouts~1history"
66
    "$ref": "paths/checkouts.json#/~1checkouts~1history"
64
  },
67
  },
(-)a/api/v1/swagger/paths/checkouts.json (+57 lines)
Lines 198-203 Link Here
198
      }
198
      }
199
    }
199
    }
200
  },
200
  },
201
  "/checkouts/expanded": {
202
    "get": {
203
      "x-mojo-to": "Checkout#expanded",
204
      "operationId": "expandedCheckouts",
205
      "tags": ["patrons", "checkouts"],
206
      "parameters": [{
207
        "$ref": "../parameters.json#/borrowernumberQueryParam"
208
      }],
209
      "produces": [
210
        "application/json"
211
      ],
212
      "responses": {
213
        "200": {
214
          "description": "A list of expanded checkouts",
215
          "schema": {
216
            "type": "array",
217
            "items": {
218
              "$ref": "../definitions.json#/checkoutexpanded"
219
            }
220
          }
221
        },
222
        "401": {
223
          "description": "Authentication required",
224
          "schema": {
225
            "$ref": "../definitions.json#/error"
226
          }
227
        },
228
        "403": {
229
          "description": "Access forbidden",
230
          "schema": { "$ref": "../definitions.json#/error" }
231
        },
232
        "404": {
233
          "description": "Patron not found",
234
          "schema": { "$ref": "../definitions.json#/error" }
235
        },
236
        "500": {
237
          "description": "Internal error",
238
          "schema": {
239
            "$ref": "../definitions.json#/error"
240
          }
241
        },
242
        "503": {
243
          "description": "Under maintenance",
244
          "schema": {
245
            "$ref": "../definitions.json#/error"
246
          }
247
        }
248
      },
249
      "x-koha-authorization": {
250
        "allow-owner": true,
251
        "allow-guarantor": true,
252
        "permissions": {
253
          "circulate": "circulate_remaining_permissions"
254
        }
255
      }
256
    }
257
  },
201
  "/checkouts/history": {
258
  "/checkouts/history": {
202
    "get": {
259
    "get": {
203
      "x-mojo-to": "Checkout#listhistory",
260
      "x-mojo-to": "Checkout#listhistory",
(-)a/t/db_dependent/api/v1/checkoutsexpanded.t (-1 / +174 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# Copyright 2017 Koha-Suomi Oy
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Test::More tests => 1;
23
use Test::Mojo;
24
use t::lib::Mocks;
25
use t::lib::TestBuilder;
26
27
use C4::Auth;
28
use C4::Circulation;
29
use C4::Context;
30
use C4::Items;
31
32
use Koha::Database;
33
34
my $schema  = Koha::Database->new->schema;
35
my $builder = t::lib::TestBuilder->new;
36
37
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
38
# this affects the other REST api tests
39
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
40
41
my $remote_address = '127.0.0.1';
42
my $t              = Test::Mojo->new('Koha::REST::V1');
43
44
# Mock userenv branchcode
45
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
46
my $module = new Test::MockModule('C4::Context');
47
$module->mock('userenv', sub { { branch => $branchcode } });
48
49
subtest 'get() tests' => sub {
50
    plan tests => 13;
51
52
    $schema->storage->txn_begin;
53
54
    # Create test context
55
    my ($borrowernumber, $sessionid)            = create_user_and_session();
56
    my ($librariannnumber, $librariansessionid) = create_user_and_session(2);
57
58
    # 1. Patrons
59
    my $patron       = Koha::Patrons->find($borrowernumber);
60
    my $librarian    = Koha::Patrons->find($librariannnumber);
61
62
    # 2. Biblios and items
63
    my $biblionumber = create_biblio('RESTful Web APIs');
64
    my $itemnumber1  = create_item($biblionumber, 'TEST1001');
65
    my $itemnumber2  = create_item($biblionumber, 'TEST1002');
66
    my $itemnumber3  = create_item($biblionumber, 'TEST1003');
67
    my $item1        = Koha::Items->find($itemnumber1);
68
    my $item2        = Koha::Items->find($itemnumber2);
69
    my $item3        = Koha::Items->find($itemnumber3);
70
71
    # 3. Checkouts
72
    my $due    = DateTime->now->add(weeks => 2);
73
    my $issue1 = C4::Circulation::AddIssue($patron->unblessed, 'TEST1001', $due);
74
    my $due2   = Koha::DateUtils::dt_from_string( $issue1->date_due );
75
    my $issue2 = C4::Circulation::AddIssue($patron->unblessed, 'TEST1002', $due2);
76
    C4::Circulation::AddRenewal($borrowernumber, $itemnumber2, $branchcode, $due2);
77
78
    # 4. Issuing rules
79
    t::lib::Mocks::mock_preference('CircControl', 'ItemHomeLibrary');
80
    t::lib::Mocks::mock_preference('HomeOrHoldingBranch', 'homebranch');
81
    Koha::IssuingRule->new({
82
        categorycode => $patron->categorycode,
83
        itemtype     => $item1->effective_itemtype,
84
        branchcode   => $item1->homebranch,
85
        renewalsallowed => 5,
86
    })->store;
87
    Koha::IssuingRule->new({
88
        categorycode => $patron->categorycode,
89
        itemtype     => $item2->effective_itemtype,
90
        branchcode   => $item2->homebranch,
91
        renewalsallowed => 10,
92
    })->store;
93
94
    # BEGIN TEST
95
96
    # Request my own expanded checkout infromation
97
    my $tx = $t->ua->build_tx(GET => "/api/v1/checkouts/expanded?borrowernumber="
98
                              .$borrowernumber);
99
    $tx->req->cookies({name =>'CGISESSID', value => $sessionid});
100
    $tx->req->env({REMOTE_ADDR => '127.0.0.1'});
101
    $t->request_ok($tx)
102
        ->status_is(200)
103
        ->json_is('/0/borrowernumber' => $borrowernumber)
104
        ->json_is('/0/itemnumber' => $itemnumber1)
105
        ->json_like('/0/date_due' => qr/$due\+\d\d:\d\d/)
106
        ->json_is('/0/renewals'   => 0)
107
        ->json_is('/0/max_renewals' => 5)
108
        ->json_is('/1/borrowernumber' => $borrowernumber)
109
        ->json_is('/1/itemnumber' => $itemnumber2)
110
        ->json_like('/1/date_due' => qr/$due2\+\d\d:\d\d/)
111
        ->json_is('/1/renewals'   => 1)
112
        ->json_is('/1/max_renewals' => 10)
113
        ->json_hasnt('/2');
114
115
    $schema->storage->txn_rollback;
116
};
117
118
sub create_user_and_session {
119
    my ($flags) = @_;
120
121
    my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
122
    my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
123
124
    my $borrower = $builder->build({
125
        source => 'Borrower',
126
        value => {
127
            branchcode   => $branchcode,
128
            categorycode => $categorycode,
129
            flags        => $flags,
130
        }
131
    });
132
133
    my $borrowersession = C4::Auth::get_session('');
134
    $borrowersession->param('number', $borrower->{ borrowernumber });
135
    $borrowersession->param('id', $borrower->{ userid });
136
    $borrowersession->param('ip', '127.0.0.1');
137
    $borrowersession->param('lasttime', time());
138
    $borrowersession->flush;
139
140
    return ($borrower->{borrowernumber}, $borrowersession->id);
141
}
142
143
sub create_biblio {
144
    my ($title) = @_;
145
146
    my $record = new MARC::Record;
147
    $record->append_fields(
148
        new MARC::Field('200', ' ', ' ', a => $title),
149
    );
150
151
    my ($biblionumber) = C4::Biblio::AddBiblio($record, '');
152
153
    return $biblionumber;
154
}
155
156
sub create_item {
157
    my ($biblionumber, $barcode) = @_;
158
159
    my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
160
161
    my $itemtype = $builder->build({
162
        source => 'Itemtype', value => { notforloan => 0 }
163
    });
164
    my $item = {
165
        barcode       => $barcode,
166
        homebranch    => $branchcode,
167
        holdingbranch => $branchcode,
168
        itype         => $itemtype->{itemtype},
169
    };
170
171
    my $itemnumber = C4::Items::AddItem($item, $biblionumber);
172
173
    return $itemnumber;
174
}

Return to bug 18407