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

(-)a/Koha/Accountline.pm (+30 lines)
Line 0 Link Here
1
package Koha::Accountline;
2
3
# Copyright 2015 BibLibre
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 Koha::Database;
23
24
use base qw(Koha::Object);
25
26
sub _type {
27
    return 'Accountline';
28
}
29
30
1;
(-)a/Koha/Accountlines.pm (+35 lines)
Line 0 Link Here
1
package Koha::Accountlines;
2
3
# Copyright 2015 BibLibre
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 Koha::Database;
23
use Koha::Accountline;
24
25
use base qw(Koha::Objects);
26
27
sub _type {
28
    return 'Accountline';
29
}
30
31
sub object_class {
32
    return 'Koha::Accountline';
33
}
34
35
1;
(-)a/Koha/Item.pm (+171 lines)
Lines 23-28 use Carp; Link Here
23
23
24
use Koha::Database;
24
use Koha::Database;
25
25
26
use C4::Context;
27
use Koha::Holds;
28
use Koha::Issues;
29
use Koha::Item::Availability;
30
use Koha::ItemTypes;
26
use Koha::Patrons;
31
use Koha::Patrons;
27
use Koha::Libraries;
32
use Koha::Libraries;
28
33
Lines 38-43 Koha::Item - Koha Item object class Link Here
38
43
39
=cut
44
=cut
40
45
46
=head3 availabilities
47
48
my $available = $item->availabilities();
49
50
Gets different availability types, generally, without considering patron status.
51
52
Returns HASH containing Koha::Item::Availability objects for each availability
53
type. Currently implemented availabilities are:
54
    * hold
55
    * checkout
56
    * local_use
57
    * onsite_checkout
58
59
=cut
60
61
sub availabilities {
62
    my ( $self, $params ) = @_;
63
64
    my $availabilities; # HASH containing different types of availabilities
65
    my $availability = Koha::Item::Availability->new->set_available;
66
67
    $availability->set_unavailable("withdrawn") if $self->withdrawn;
68
    $availability->set_unavailable("itemlost") if $self->itemlost;
69
    $availability->set_unavailable("restricted") if $self->restricted;
70
71
    if ($self->damaged) {
72
        if (C4::Context->preference('AllowHoldsOnDamagedItems')) {
73
            $availability->add_description("damaged");
74
        } else {
75
            $availability->set_unavailable("damaged");
76
        }
77
    }
78
79
    my $itemtype;
80
    if (C4::Context->preference('item-level_itypes')) {
81
        $itemtype = Koha::ItemTypes->find( $self->itype );
82
    } else {
83
        my $biblioitem = Koha::Biblioitems->find( $self->biblioitemnumber );
84
        $itemtype = Koha::ItemTypes->find( $biblioitem->itemype );
85
    }
86
87
    if ($self->notforloan > 0 || $itemtype && $itemtype->notforloan) {
88
        $availability->set_unavailable("notforloan");
89
    } elsif ($self->notforloan < 0) {
90
        $availability->set_unavailable("ordered");
91
    }
92
93
    # Hold
94
    $availabilities->{'hold'} = $availability->clone;
95
96
    # Checkout
97
    if ($self->onloan) {
98
        my $issue = Koha::Issues->search({ itemnumber => $self->itemnumber })->next;
99
        $availability->set_unavailable("onloan", $issue->date_due) if $issue;
100
    }
101
102
    if (Koha::Holds->search( [
103
            { itemnumber => $self->itemnumber },
104
            { found => [ '=', 'W', 'T' ] }
105
            ])->count()) {
106
        $availability->set_unavailable("reserved");
107
    }
108
109
    $availabilities->{'checkout'} = $availability->clone;
110
111
    # Local Use,
112
    if (grep(/^notforloan$/, @{$availability->{description}})
113
        && @{$availability->{description}} == 1) {
114
        $availabilities->{'local_use'} = $availability->clone->set_available
115
                                            ->del_description("notforloan");
116
    } else {
117
        $availabilities->{'local_use'} = $availability->clone
118
                                            ->del_description("notforloan");
119
    }
120
121
    # On-site checkout
122
    if (!C4::Context->preference('OnSiteCheckouts')) {
123
        $availabilities->{'onsite_checkout'}
124
        = Koha::Item::Availability->new
125
        ->set_unavailable("onsite_checkouts_disabled");
126
    } else {
127
        $availabilities->{'onsite_checkout'}
128
        = $availabilities->{'local_use'}->clone;
129
    }
130
131
    return $availabilities;
132
}
133
134
=head3 availability_for_checkout
135
136
my $available = $item->availability_for_checkout();
137
138
Gets checkout availability of the item. This subroutine does not check patron
139
status, instead the purpose is to check general availability for this item.
140
141
Returns Koha::Item::Availability object.
142
143
=cut
144
145
sub availability_for_checkout {
146
    my ( $self ) = @_;
147
148
    return $self->availabilities->{'checkout'};
149
}
150
151
=head3 availability_for_local_use
152
153
my $available = $item->availability_for_local_use();
154
155
Gets local use availability of the item.
156
157
Returns Koha::Item::Availability object.
158
159
=cut
160
161
sub availability_for_local_use {
162
    my ( $self ) = @_;
163
164
    return $self->availabilities->{'local_use'};
165
}
166
167
=head3 availability_for_onsite_checkout
168
169
my $available = $item->availability_for_onsite_checkout();
170
171
Gets on-site checkout availability of the item.
172
173
Returns Koha::Item::Availability object.
174
175
=cut
176
177
sub availability_for_onsite_checkout {
178
    my ( $self ) = @_;
179
180
    return $self->availabilities->{'onsite_checkout'};
181
}
182
183
=head3 availability_for_reserve
184
185
my $available = $item->availability_for_reserve();
186
187
Gets reserve availability of the item. This subroutine does not check patron
188
status, instead the purpose is to check general availability for this item.
189
190
Returns Koha::Item::Availability object.
191
192
=cut
193
194
sub availability_for_reserve {
195
    my ( $self ) = @_;
196
197
    return $self->availabilities->{'hold'};
198
}
199
41
=head3 effective_itemtype
200
=head3 effective_itemtype
42
201
43
Returns the itemtype for the item based on whether item level itemtypes are set or not.
202
Returns the itemtype for the item based on whether item level itemtypes are set or not.
Lines 50-55 sub effective_itemtype { Link Here
50
    return $self->_result()->effective_itemtype();
209
    return $self->_result()->effective_itemtype();
51
}
210
}
52
211
212
=head3 hold_queue_length
213
214
=cut
215
216
sub hold_queue_length {
217
    my ( $self ) = @_;
218
219
    my $reserves = Koha::Holds->search({ itemnumber => $self->itemnumber });
220
    return $reserves->count() if $reserves;
221
    return 0;
222
}
223
53
=head3 home_branch
224
=head3 home_branch
54
225
55
=cut
226
=cut
(-)a/Koha/Item/Availability.pm (+283 lines)
Line 0 Link Here
1
package Koha::Item::Availability;
2
3
# Copyright KohaSuomi 2016
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 Storable qw(dclone);
23
24
=head1 NAME
25
26
Koha::Item::Availability - Koha Item Availability object class
27
28
=head1 SYNOPSIS
29
30
  my $item = Koha::Items->find(1337);
31
  my $availabilities = $item->availabilities();
32
  # ref($availabilities) eq 'HASH'
33
  # ref($availabilities->{'checkout'}) eq 'Koha::Item::Availability'
34
35
  print "Available for checkout!" if $availabilities->{'checkout'}->{available};
36
37
=head1 DESCRIPTION
38
39
This class holds item availability information.
40
41
See Koha::Item for availability subroutines.
42
43
=head2 Class Methods
44
45
=cut
46
47
=head3 new
48
49
Returns a new Koha::Item::Availability object.
50
51
=cut
52
53
sub new {
54
    my ( $class ) = @_;
55
56
    my $self = {
57
        description        => [],
58
        availability_needs_confirmation => undef,
59
        available                       => undef,
60
        expected_available              => undef,
61
    };
62
63
    bless( $self, $class );
64
}
65
66
=head3 add_description
67
68
$availability->add_description("notforloan");
69
$availability->add_description("withdrawn);
70
71
# $availability->{description} = ["notforloan", "withdrawn"]
72
73
Pushes a new description to $availability object. Does not duplicate existing
74
descriptions.
75
76
Returns updated Koha::Item::Availability object.
77
78
=cut
79
80
sub add_description {
81
    my ($self, $description) = @_;
82
83
    return $self unless $description;
84
85
    if (ref($description) eq 'ARRAY') {
86
        foreach my $desc (@$description) {
87
            if (grep(/^$desc$/, @{$self->{description}})){
88
                next;
89
            }
90
            push $self->{description}, $desc;
91
        }
92
    } else {
93
        if (!grep(/^$description$/, @{$self->{description}})){
94
            push $self->{description}, $description;
95
        }
96
    }
97
98
    return $self;
99
}
100
101
=head3 clone
102
103
$availability_cloned = $availability->clone;
104
$availability->set_unavailable;
105
106
# $availability_cloned->{available} != $availability->{available}
107
108
Clones the Koha::Item::Availability object.
109
110
Returns cloned object.
111
112
=cut
113
114
sub clone {
115
    my ( $self ) = @_;
116
117
    return dclone($self);
118
}
119
120
=head3 del_description
121
122
$availability->add_description(["notforloan", "withdrawn", "itemlost", "restricted"]);
123
$availability->del_description("withdrawn");
124
125
# $availability->{description} == ["notforloan", "itemlost", "restricted"]
126
$availability->del_description(["withdrawn", "restricted"]);
127
# $availability->{description} == ["itemlost"]
128
129
Deletes an availability description(s) if it exists.
130
131
Returns (possibly updated) Koha::Item::Availability object.
132
133
=cut
134
135
sub del_description {
136
    my ($self, $description) = @_;
137
138
    return $self unless $description;
139
140
    my @updated;
141
    if (ref($description) eq 'ARRAY') {
142
        foreach my $desc (@$description) {
143
            @updated = grep(!/^$desc$/, @{$self->{description}});
144
        }
145
    } else {
146
        @updated = grep(!/^$description$/, @{$self->{description}});
147
    }
148
    $self->{description} = \@updated;
149
150
    return $self;
151
}
152
153
=head3 hash_description
154
155
$availability->add_description(["notforloan", "withdrawn"]);
156
$availability->has_description("withdrawn"); # 1
157
$availability->has_description(["notforloan", "withdrawn"]); # 1
158
$availability->has_description("itemlost"); # 0
159
160
Finds description(s) in availability descriptions.
161
162
Returns 1 if found, 0 otherwise.
163
164
=cut
165
166
sub has_description {
167
    my ($self, $description) = @_;
168
169
    return 0 unless $description;
170
171
    my @found;
172
    if (ref($description) eq 'ARRAY') {
173
        foreach my $desc (@$description) {
174
            if (!grep(/^$desc$/, @{$self->{description}})){
175
                return 0;
176
            }
177
        }
178
    } else {
179
        if (!grep(/^$description$/, @{$self->{description}})){
180
            return 0;
181
        }
182
    }
183
184
    return 1;
185
}
186
187
=head3 reset
188
189
$availability->reset;
190
191
Resets the object.
192
193
=cut
194
195
sub reset {
196
    my ( $self ) = @_;
197
198
    $self->{available} = undef;
199
    $self->{availability_needs_confirmation} = undef;
200
    $self->{expected_available} = undef;
201
    $self->{description} = [];
202
    return $self;
203
}
204
205
=head3 set_available
206
207
$availability->set_available;
208
209
Sets the Koha::Item::Availability object status to available.
210
   $availability->{available} == 1
211
212
Overrides old availability status, but does not override other stored data in
213
the object. Create a new Koha::Item::Availability object to get a fresh start.
214
Appends any previously defined availability descriptions with add_description().
215
216
Returns updated Koha::Item::Availability object.
217
218
=cut
219
220
sub set_available {
221
    my ($self, $description) = @_;
222
223
    return $self->_update_availability_status(1, 0, $description);
224
}
225
226
=head3 set_needs_confirmation
227
228
$availability->set_needs_confirmation("unbelieveable_reason", "2016-07-07");
229
230
Sets the Koha::Item::Availability object status to unavailable,
231
but needs confirmation.
232
   $availability->{available} == 0
233
   $availability->{availability_needs_confirmation} == 1
234
235
Overrides old availability statuses, but does not override other stored data in
236
the object. Create a new Koha::Item::Availability object to get a fresh start.
237
Appends any previously defined availability descriptions with add_description().
238
Allows you to define expected availability date in C<$expected>.
239
240
Returns updated Koha::Item::Availability object.
241
242
=cut
243
244
sub set_needs_confirmation {
245
    my ($self, $description, $expected) = @_;
246
247
    return $self->_update_availability_status(0, 1, $description, $expected);
248
}
249
250
=head3 set_unavailable
251
252
$availability->set_unavailable("onloan", "2016-07-07");
253
254
Sets the Koha::Item::Availability object status to unavailable.
255
   $availability->{available} == 0
256
257
Overrides old availability status, but does not override other stored data in
258
the object. Create a new Koha::Item::Availability object to get a fresh start.
259
Appends any previously defined availability descriptions with add_description().
260
Allows you to define expected availability date in C<$expected>.
261
262
Returns updated Koha::Item::Availability object.
263
264
=cut
265
266
sub set_unavailable {
267
    my ($self, $description, $expected) = @_;
268
269
    return $self->_update_availability_status(0, 0, $description, $expected);
270
}
271
272
sub _update_availability_status {
273
    my ( $self, $available, $needs, $desc, $expected ) = @_;
274
275
    $self->{available} = $available;
276
    $self->{availability_needs_confirmation} = $needs;
277
    $self->{expected_available} = $expected if $expected;
278
    $self->add_description($desc);
279
280
    return $self;
281
}
282
283
1;
(-)a/Koha/REST/V1/Accountline.pm (+144 lines)
Line 0 Link Here
1
package Koha::REST::V1::Accountline;
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::Accounts qw( makepayment makepartialpayment recordpayment );
24
use C4::Members qw( GetMember );
25
use Koha::Accountlines;
26
use Scalar::Util qw( looks_like_number );
27
28
sub list {
29
    my ($c, $args, $cb) = @_;
30
31
    my $user = $c->stash('koha.user');
32
    unless ($user && haspermission($user->userid, {updatecharges => 1})) {
33
        return $c->$cb({error => "You don't have the required permission"}, 403);
34
    }
35
36
    my $params  = $c->req->params->to_hash;
37
    my $accountlines = Koha::Accountlines->search($params);
38
39
    return $c->$cb($accountlines->unblessed, 200);
40
}
41
42
43
sub edit {
44
    my ($c, $args, $cb) = @_;
45
46
    my $user = $c->stash('koha.user');
47
    unless ($user && haspermission($user->userid, {updatecharges => 1})) {
48
        return $c->$cb({error => "You don't have the required permission"}, 403);
49
    }
50
51
    my $accountline = Koha::Accountlines->find($args->{accountlines_id});
52
    unless ($accountline) {
53
        return $c->$cb({error => "Accountline not found"}, 404);
54
    }
55
56
    my $body = $c->req->json;
57
58
    $accountline->set( $body );
59
    $accountline->store();
60
61
    return $c->$cb($accountline->unblessed(), 200);
62
}
63
64
65
sub pay {
66
    my ($c, $args, $cb) = @_;
67
68
    my $user = $c->stash('koha.user');
69
    unless ($user && haspermission($user->userid, {updatecharges => 1})) {
70
        return $c->$cb({error => "You don't have the required permission"}, 403);
71
    }
72
73
    my $accountline = Koha::Accountlines->find($args->{accountlines_id});
74
    unless ($accountline) {
75
        return $c->$cb({error => "Accountline not found"}, 404);
76
    }
77
78
    makepayment($accountline->accountlines_id,
79
                $accountline->borrowernumber,
80
                $accountline->accountno,
81
                $accountline->amount);
82
83
    $accountline = Koha::Accountlines->find($args->{accountlines_id});
84
    return $c->$cb($accountline->unblessed(), 200);
85
}
86
87
sub partialpay {
88
    my ($c, $args, $cb) = @_;
89
90
    my $user = $c->stash('koha.user');
91
    unless ($user && haspermission($user->userid, {updatecharges => 1})) {
92
        return $c->$cb({error => "You don't have the required permission"}, 403);
93
    }
94
95
    my $accountline = Koha::Accountlines->find($args->{accountlines_id});
96
    unless ($accountline) {
97
        return $c->$cb({error => "Accountline not found"}, 404);
98
    }
99
100
    my $body = $c->req->json;
101
    my $amount = $body->{amount};
102
    my $note = $body->{note} || '';
103
104
    unless ($amount && looks_like_number($amount)) {
105
        return $c->$cb({error => "Invalid amount"}, 400);
106
    }
107
108
    makepartialpayment($accountline->accountlines_id,
109
                       $accountline->borrowernumber,
110
                       $accountline->accountno,
111
                       $amount, '', '', $note);
112
113
    $accountline = Koha::Accountlines->find($args->{accountlines_id});
114
    return $c->$cb($accountline->unblessed(), 200);
115
}
116
117
118
sub payamount   {
119
    my ($c, $args, $cb) = @_;
120
121
    my $user = $c->stash('koha.user');
122
    unless ($user && haspermission($user->userid, {updatecharges => 1})) {
123
        return $c->$cb({error => "You don't have the required permission"}, 403);
124
    }
125
126
    my $borrower = GetMember(borrowernumber => $args->{borrowernumber});
127
    unless ($borrower) {
128
        return $c->$cb({error => "Borrower not found"}, 404);
129
    }
130
131
    my $body = $c->req->json;
132
    my $amount = $body->{amount};
133
    my $note = $body->{note} || '';
134
135
    unless ($amount && looks_like_number($amount)) {
136
        return $c->$cb({error => "Invalid amount"}, 400);
137
    }
138
139
    recordpayment($borrower->{borrowernumber}, $amount, '', $note);
140
141
    return $c->$cb({amount => $amount}, 200);
142
}
143
144
1;
(-)a/Koha/REST/V1/Availability.pm (+99 lines)
Line 0 Link Here
1
package Koha::REST::V1::Availability;
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 Koha::Holds;
24
use Koha::Items;
25
26
sub items {
27
    my ($c, $args, $cb) = @_;
28
29
    my @items;
30
    if ($args->{'itemnumber'}) {
31
        push @items, _item_availability(@{$args->{'itemnumber'}});
32
    }
33
    if ($args->{'biblionumber'}) {
34
        my $found_items = Koha::Items->search({ biblionumber => {
35
                            '=', \@{$args->{'biblionumber'}}
36
                            } })->as_list();
37
        my @itemnumbers;
38
        foreach my $item (@$found_items) {
39
            push @itemnumbers, $item->itemnumber;
40
        }
41
42
        push @items, _item_availability(@itemnumbers);
43
    }
44
45
    return $c->$cb({ error => "Item(s) not found"}, 404) unless scalar @items;
46
    return $c->$cb([ @items ], 200);
47
}
48
49
sub _item_availability {
50
    my (@itemnumbers) = @_;
51
52
    my @items;
53
54
    foreach my $itemnumber (@itemnumbers) {
55
        my $item = Koha::Items->find($itemnumber);
56
57
        unless ($item) {
58
            next;
59
        }
60
61
        my $availabilities = _swaggerize_availabilities($item->availabilities());
62
63
        my $holds;
64
        $holds->{'hold_queue_length'} = $item->hold_queue_length();
65
66
        my $iteminfo = {
67
            itemnumber => $item->itemnumber,
68
            barcode => $item->barcode,
69
            biblionumber => $item->biblionumber,
70
            biblioitemnumber => $item->biblioitemnumber,
71
            holdingbranch => $item->holdingbranch,
72
            homebranch => $item->homebranch,
73
            location => $item->location,
74
            itemcallnumber => $item->itemcallnumber,
75
        };
76
77
        # merge availability, hold information and item information
78
        push @items, { %{$availabilities}, %{$holds}, %{$iteminfo} };
79
    }
80
81
    return @items;
82
}
83
84
sub _swaggerize_availabilities {
85
    my ($availabilities) = @_;
86
87
    foreach my $availability (keys $availabilities) {
88
        delete $availabilities->{$availability}->{availability_needs_confirmation};
89
        $availabilities->{$availability}->{available} =
90
        $availabilities->{$availability}->{available}
91
                             ? Mojo::JSON->true
92
                             : Mojo::JSON->false;
93
        $availabilities->{$availability} = { %{$availabilities->{$availability}} };
94
    }
95
96
    return $availabilities;
97
}
98
99
1;
(-)a/Koha/REST/V1/Biblio.pm (+76 lines)
Line 0 Link Here
1
package Koha::REST::V1::Biblio;
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 strict;
19
use warnings;
20
21
use Modern::Perl;
22
23
use Mojo::Base 'Mojolicious::Controller';
24
use Mojo::JSON;
25
26
use C4::Auth qw( haspermission );
27
use C4::Context;
28
use C4::Items qw( GetItem GetHiddenItemnumbers );
29
30
use Koha::Biblios;
31
use Koha::Items;
32
33
sub get {
34
    my ($c, $args, $cb) = @_;
35
36
    my $biblionumber = $c->param('biblionumber');
37
    my $biblio = Koha::Biblios->find($biblionumber);
38
39
    unless ($biblio) {
40
      return $c->$cb({error => "Biblio not found"}, 404);
41
    }
42
43
    my $items ||= Koha::Items->search( { biblionumber => $biblionumber }, {
44
      columns => [qw/itemnumber/],
45
    })->unblessed;
46
47
    my $user = $c->stash('koha.user');
48
    my $isStaff = haspermission($user->userid, {borrowers => 1});
49
50
    # Hide the hidden items from all but staff
51
    my $opachiddenitems = ! $isStaff
52
      && ( C4::Context->preference('OpacHiddenItems') !~ /^\s*$/ );
53
54
    if ($opachiddenitems) {
55
56
      my @hiddenitems = C4::Items::GetHiddenItemnumbers( @{$items} );
57
58
      my @filteredItems = ();
59
60
      # Convert to a hash for quick searching
61
      my %hiddenitems = map { $_ => 1 } @hiddenitems;
62
      foreach my $itemnumber ( map { $_->{itemnumber} } @{$items} ) {
63
          next if $hiddenitems{$itemnumber};
64
          push @filteredItems, { itemnumber => $itemnumber };
65
      }
66
67
      $items = \@filteredItems;
68
    }
69
70
    $biblio = $biblio->unblessed;
71
    $biblio->{items} = $items;
72
73
    return $c->$cb($biblio, 200);
74
}
75
76
1;
(-)a/Koha/REST/V1/Checkout.pm (+159 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::Context;
24
use C4::Circulation;
25
use Koha::Issues;
26
use Koha::OldIssues;
27
28
sub list {
29
    my ($c, $args, $cb) = @_;
30
31
    my $user = $c->stash('koha.user');
32
    unless ($user && ($user->borrowernumber == $c->param('borrowernumber')
33
            || haspermission($user->userid, { circulate => "circulate_remaining_permissions" }))) {
34
        return $c->$cb({error => "You don't have the required permission"}, 403);
35
    }
36
37
    my $borrowernumber = $c->param('borrowernumber');
38
    my $checkouts = C4::Circulation::GetIssues({
39
        borrowernumber => $borrowernumber
40
    });
41
42
    $c->$cb($checkouts, 200);
43
}
44
45
sub get {
46
    my ($c, $args, $cb) = @_;
47
48
    my $user = $c->stash('koha.user');
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
    my $borrowernumber = $checkout->borrowernumber;
60
61
    unless ($user && ( $user->borrowernumber == $borrowernumber
62
            || haspermission($user->userid, { circulate => "circulate_remaining_permissions" }))) {
63
        return $c->$cb({error => "You don't have the required permission"}, 403);
64
    }
65
66
    return $c->$cb($checkout->unblessed, 200);
67
}
68
69
sub renew {
70
    my ($c, $args, $cb) = @_;
71
72
    my $user = $c->stash('koha.user');
73
74
    my $checkout_id = $args->{checkout_id};
75
    my $checkout = Koha::Issues->find($checkout_id);
76
77
    if (!$checkout) {
78
        return $c->$cb({
79
            error => "Checkout doesn't exist"
80
        }, 404);
81
    }
82
83
    $checkout = $checkout->unblessed;
84
85
    my $borrowernumber = $checkout->borrowernumber;
86
    my $itemnumber = $checkout->itemnumber;
87
88
    my $OpacRenewalAllowed;
89
    if ($user->borrowernumber == $borrowernumber) {
90
        $OpacRenewalAllowed = C4::Context->preference('OpacRenewalAllowed');
91
    }
92
93
    unless ($user && ($OpacRenewalAllowed
94
            || haspermission($user->userid, { circulate => "circulate_remaining_permissions" }))) {
95
        return $c->$cb({error => "You don't have the required permission"}, 403);
96
    }
97
98
    my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
99
        $borrowernumber, $itemnumber);
100
101
    if (!$can_renew) {
102
        return $c->$cb({error => "Renewal not authorized ($error)"}, 403);
103
    }
104
105
    AddRenewal($borrowernumber, $itemnumber, $checkout->branchcode);
106
    $checkout = Koha::Issues->find($checkout_id);
107
108
    return $c->$cb($checkout->unblessed, 200);
109
}
110
111
sub listhistory {
112
    my ($c, $args, $cb) = @_;
113
114
    my $user = $c->stash('koha.user');
115
    unless ($user && haspermission($user->userid, { circulate => "circulate_remaining_permissions" })) {
116
        return $c->$cb({error => "You don't have the required permission"}, 403);
117
    }
118
119
    my $borrowernumber = $c->param('borrowernumber');
120
121
    my %attributes = ( itemnumber => { "!=", undef } );
122
    if ($borrowernumber) {
123
        return $c->$cb({
124
            error => "Patron doesn't exist"
125
        }, 404) unless Koha::Patrons->find($borrowernumber);
126
127
        $attributes{borrowernumber} = $borrowernumber;
128
    }
129
130
    # Retrieve all the issues in the history, but only the issue_id due to possible perfomance issues
131
    my $checkouts = Koha::OldIssues->search(
132
      \%attributes,
133
      { columns => [qw/issue_id/]}
134
    );
135
136
    $c->$cb($checkouts->unblessed, 200);
137
}
138
139
sub gethistory {
140
    my ($c, $args, $cb) = @_;
141
142
    my $user = $c->stash('koha.user');
143
    unless ($user && haspermission($user->userid, { circulate => "circulate_remaining_permissions" })) {
144
        return $c->$cb({error => "You don't have the required permission"}, 403);
145
    }
146
147
    my $checkout_id = $args->{checkout_id};
148
    my $checkout = Koha::OldIssues->find($checkout_id);
149
150
    if (!$checkout) {
151
        return $c->$cb({
152
            error => "Checkout doesn't exist"
153
        }, 404);
154
    }
155
156
    return $c->$cb($checkout->unblessed, 200);
157
}
158
159
1;
(-)a/Koha/REST/V1/Item.pm (+54 lines)
Line 0 Link Here
1
package Koha::REST::V1::Item;
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::Items qw( GetHiddenItemnumbers );
25
26
use Koha::Items;
27
28
sub get {
29
    my ($c, $args, $cb) = @_;
30
31
    my $itemnumber = $c->param('itemnumber');
32
    my $item = Koha::Items->find($itemnumber);
33
    unless ($item) {
34
        return $c->$cb({error => "Item not found"}, 404);
35
    }
36
37
    # Hide non-public itemnotes if user has no staff access
38
    my $user = $c->stash('koha.user');
39
    unless ($user && haspermission($user->userid, {catalogue => 1})) {
40
41
        my @hiddenitems = C4::Items::GetHiddenItemnumbers( ({ itemnumber => $itemnumber}) );
42
        my %hiddenitems = map { $_ => 1 } @hiddenitems;
43
44
	# Pretend it was not found as it's hidden from OPAC to regular users
45
        return $c->$cb({error => "Item not found"}, 404)
46
          if $hiddenitems{$itemnumber};
47
48
        $item->set({ itemnotes_nonpublic => undef });
49
    }
50
51
    return $c->$cb($item->unblessed, 200);
52
}
53
54
1;
(-)a/Koha/REST/V1/Library.pm (+42 lines)
Line 0 Link Here
1
package Koha::REST::V1::Library;
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 Koha::Libraries;
22
23
sub list {
24
    my ($c, $args, $cb) = @_;
25
26
    my $libraries = Koha::Libraries->search;
27
    return $c->$cb($libraries->unblessed, 200);
28
}
29
30
sub get {
31
    my ($c, $args, $cb) = @_;
32
33
    my $brancocode = $c->param('branchcode');
34
    my $library = Koha::Libraries->find({branchcode => $brancocode});
35
    unless ($library) {
36
        return $c->$cb({error => "Library with branchcode \"$brancocode\" not found"}, 404);
37
    }
38
39
    return $c->$cb($library->unblessed, 200);
40
}
41
42
1;
(-)a/Koha/REST/V1/Patron.pm (-1 / +156 lines)
Lines 20-26 use Modern::Perl; Link Here
20
use Mojo::Base 'Mojolicious::Controller';
20
use Mojo::Base 'Mojolicious::Controller';
21
21
22
use C4::Auth qw( haspermission );
22
use C4::Auth qw( haspermission );
23
use Koha::AuthUtils qw(hash_password);
23
use Koha::Patrons;
24
use Koha::Patrons;
25
use Koha::Patron::Categories;
26
use Koha::Libraries;
24
27
25
sub list {
28
sub list {
26
    my ($c, $args, $cb) = @_;
29
    my ($c, $args, $cb) = @_;
Lines 30-36 sub list { Link Here
30
        return $c->$cb({error => "You don't have the required permission"}, 403);
33
        return $c->$cb({error => "You don't have the required permission"}, 403);
31
    }
34
    }
32
35
33
    my $patrons = Koha::Patrons->search;
36
    my $params = $c->req->query_params->to_hash;
37
    my $patrons;
38
    if (keys %$params) {
39
        my @valid_params = Koha::Patrons->_resultset->result_source->columns;
40
        foreach my $key (keys %$params) {
41
            delete $params->{$key} unless grep { $key eq $_ } @valid_params;
42
        }
43
        $patrons = Koha::Patrons->search($params);
44
    } else {
45
        $patrons = Koha::Patrons->search;
46
    }
34
47
35
    $c->$cb($patrons->unblessed, 200);
48
    $c->$cb($patrons->unblessed, 200);
36
}
49
}
Lines 55-58 sub get { Link Here
55
    return $c->$cb($patron->unblessed, 200);
68
    return $c->$cb($patron->unblessed, 200);
56
}
69
}
57
70
71
sub add {
72
    my ($c, $args, $cb) = @_;
73
74
    my $user = $c->stash('koha.user');
75
76
    unless ( $user && haspermission($user->userid, {borrowers => 1}) ) {
77
        return $c->$cb({error => "You don't have the required permission"}, 403);
78
    }
79
80
    my $body = $c->req->json;
81
82
    # patron cardnumber and/or userid unique?
83
    if ($body->{cardnumber} || $body->{userid}) {
84
        my $patron = Koha::Patrons->find({cardnumber => $body->{cardnumber}, userid => $body->{userid} });
85
        if ($patron) {
86
            return $c->$cb({
87
                error => "Patron cardnumber and userid must be unique",
88
                conflict => { cardnumber => $patron->cardnumber, userid => $patron->userid }
89
            }, 409);
90
        }
91
    }
92
93
    my $branch = Koha::Libraries->find({branchcode => $body->{branchcode} });
94
    unless ($branch) {
95
        return $c->$cb({error => "Library with branchcode \"" . $body->{branchcode} . "\" does not exist"}, 404);
96
    }
97
    my $category = Koha::Patron::Categories->find({ categorycode => $body->{categorycode} });
98
    unless ($category) {
99
        return $c->$cb({error => "Patron category \"" . $body->{categorycode} . "\" does not exist"}, 404);
100
    }
101
    # All OK - save new patron
102
103
    if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
104
105
    my $patron = eval {
106
        Koha::Patron->new($body)->store;
107
    };
108
109
    unless ($patron) {
110
        return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
111
    }
112
113
    return $c->$cb($patron->unblessed, 201);
114
}
115
116
sub edit {
117
    my ($c, $args, $cb) = @_;
118
119
    my $user = $c->stash('koha.user');
120
121
    unless ( $user && haspermission($user->userid, {borrowers => 1}) ) {
122
        return $c->$cb({error => "You don't have the required permission"}, 403);
123
    }
124
125
    my $patron = Koha::Patrons->find($args->{borrowernumber});
126
127
    unless ($patron) {
128
        return $c->$cb({error => "Patron not found"}, 404);
129
    }
130
131
    my $body = $c->req->json;
132
133
    # Can we change userid and/or cardnumber? in that case check that they are altered first
134
    if ($body->{cardnumber} || $body->{userid}) {
135
        if ( ($body->{cardnumber} && $body->{cardnumber} ne $patron->cardnumber) || ($body->{userid} && $body->{userid} ne $patron->userid) ) {
136
            my $conflictingPatron = Koha::Patrons->find({cardnumber => $body->{cardnumber}, userid => $body->{userid} });
137
            if ($conflictingPatron) {
138
                return $c->$cb({
139
                    error => "Patron cardnumber and userid must be unique",
140
                    conflict => { cardnumber => $conflictingPatron->cardnumber, userid => $conflictingPatron->userid }
141
                }, 409);
142
            }
143
        }
144
    }
145
146
    if ($body->{branchcode}) {
147
        my $branch = Koha::Libraries->find({branchcode => $body->{branchcode} });
148
        unless ($branch) {
149
            return $c->$cb({error => "Library with branchcode \"" . $body->{branchcode} . "\" does not exist"}, 404);
150
        }
151
    }
152
153
    if ($body->{categorycode}) {
154
        my $category = Koha::Patron::Categories->find({ categorycode => $body->{categorycode} });
155
        unless ($category) {
156
            return $c->$cb({error => "Patron category \"" . $body->{categorycode} . "\" does not exist"}, 404);
157
        }
158
    }
159
    # ALL OK - Update patron
160
    # Perhaps limit/validate what should be updated here? flags, et.al.
161
    if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
162
163
    my $updatedpatron = eval {
164
        $patron->set($body);
165
    };
166
167
    if ($updatedpatron) {
168
        if ($updatedpatron->is_changed) {
169
170
            my $res = eval {
171
                $updatedpatron->store;
172
            };
173
174
            unless ($res) {
175
                return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
176
            }
177
            return $c->$cb($res->unblessed, 200);
178
179
        } else {
180
            return $c->$cb({}, 204); # No Content = No changes made
181
        }
182
    } else {
183
        return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
184
    }
185
}
186
187
sub delete {
188
    my ($c, $args, $cb) = @_;
189
    my $user = $c->stash('koha.user');
190
191
    unless ( $user && haspermission($user->userid, {borrowers => 1}) ) {
192
        return $c->$cb({error => "You don't have the required permission"}, 403);
193
    }
194
195
    my $patron = Koha::Patrons->find($args->{borrowernumber});
196
197
    unless ($patron) {
198
        return $c->$cb({error => "Patron not found"}, 404);
199
    }
200
201
    # check if loans, reservations, debarrment, etc. before deletion!
202
    my $res = $patron->delete;
203
204
    if ($res eq '1') {
205
        return $c->$cb({}, 200);
206
    } elsif ($res eq '-1') {
207
        return $c->$cb({}, 404);
208
    } else {
209
        return $c->$cb({}, 400);
210
    }
211
}
212
58
1;
213
1;
(-)a/api/v1/definitions/accountline.json (+56 lines)
Line 0 Link Here
1
{
2
    "type": "object",
3
        "properties": {
4
            "accountlines_id": {
5
                "description": "Internal account line identifier"
6
            },
7
            "borrowernumber": {
8
                "description": "Internal borrower identifier"
9
            },
10
            "accountno": {
11
                "description": "?"
12
            },
13
            "itemnumber": {
14
                "description": "Internal item identifier"
15
            },
16
            "date": {
17
                "description": "Date when the account line was created"
18
            },
19
            "time": {
20
                "description": "Time when the account line was created"
21
            },
22
            "amount": {
23
                "description": "Amount"
24
            },
25
            "description": {
26
                "description": "Description of account line"
27
            },
28
            "accounttype": {
29
                "description": "Type of accountline"
30
            },
31
            "amountoutstanding": {
32
                "description": "Amount outstanding"
33
            },
34
            "lastincrement": {
35
                "description": "?"
36
            },
37
            "timestamp": {
38
                "description": "When the account line was last updated"
39
            },
40
            "notify_id": {
41
                "description": "?"
42
            },
43
            "notify_level": {
44
                "description": "?"
45
            },
46
            "note": {
47
                "description": "Accountline note"
48
            },
49
            "manager_id": {
50
                "description": "Borrowernumber of user that created the account line"
51
            },
52
            "meansofpayment": {
53
                "description": "Means of payment"
54
            }
55
      }
56
}
(-)a/api/v1/definitions/amountpaid.json (+9 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "amount": {
5
      "type": "number",
6
      "description": "Amount paid"
7
    }
8
  }
9
}
(-)a/api/v1/definitions/availabilities.json (+4 lines)
Line 0 Link Here
1
{
2
  "type": "array",
3
  "items": { "$ref": "availability.json" }
4
}
(-)a/api/v1/definitions/availability.json (+57 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "barcode": {
5
      "type": ["string", "null"],
6
      "description": "item barcode"
7
    },
8
    "biblioitemnumber": {
9
      "type": "string",
10
      "description": "internally assigned biblio item identifier"
11
    },
12
    "biblionumber": {
13
      "type": "string",
14
      "description": "internally assigned biblio identifier"
15
    },
16
    "checkout": {
17
      "$ref": "availabilitystatus.json"
18
    },
19
    "expected_available": {
20
      "type": ["string", "null"],
21
      "description": "date this item is expected to be available"
22
    },
23
    "hold": {
24
      "$ref": "availabilitystatus.json"
25
    },
26
    "holdQueueLength": {
27
      "type": ["integer", "null"],
28
      "description": "number of holdings placed on title/item"
29
    },
30
    "holdingbranch": {
31
      "type": ["string", "null"],
32
      "description": "library that is currently in possession item"
33
    },
34
    "homebranch": {
35
      "type": ["string", "null"],
36
      "description": "library that owns this item"
37
    },
38
    "itemcallnumber": {
39
      "type": ["string", "null"],
40
      "description": "call number for this item"
41
    },
42
    "itemnumber": {
43
      "type": "string",
44
      "description": "internally assigned item identifier"
45
    },
46
    "local_use": {
47
      "$ref": "availabilitystatus.json"
48
    },
49
    "location": {
50
      "type": ["string", "null"],
51
      "description": "authorized value for the shelving location for this item"
52
    },
53
    "onsite_checkout": {
54
      "$ref": "availabilitystatus.json"
55
    }
56
  }
57
}
(-)a/api/v1/definitions/availabilitystatus.json (+16 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "available": {
5
      "type": "boolean",
6
      "description": "availability status"
7
    },
8
    "description": {
9
      "type": "array",
10
      "items": {
11
        "type": ["string", "null"],
12
        "description": "more information on availability"
13
      }
14
    }
15
  }
16
}
(-)a/api/v1/definitions/biblio.json (+65 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "biblionumber": {
5
      "type": "string",
6
      "description": "internal bibliographic record identifier"
7
    },
8
    "frameworkcode": {
9
      "type": "string",
10
      "description": "foreign key from the biblio_framework table to identify which framework was used in cataloging this record"
11
    },
12
    "author": {
13
      "type": ["string", "null"],
14
      "description": "statement of responsibility from MARC record (100$a in MARC21)"
15
    },
16
    "title": {
17
      "type": ["string", "null"],
18
      "description": "title (without the subtitle) from the MARC record (245$a in MARC21)"
19
    },
20
    "untitle": {
21
      "type": ["string", "null"],
22
      "description": "uniform title (without the subtitle) from the MARC record (240$a in MARC21)"
23
    },
24
    "notes": {
25
      "type": ["string", "null"],
26
      "description": "values from the general notes field in the MARC record (500$a in MARC21) split by bar (|)"
27
    },
28
    "serial": {
29
      "type": ["string", "null"],
30
      "description": "Boolean indicating whether biblio is for a serial"
31
    },
32
    "seriestitle": {
33
      "type": ["string", "null"],
34
      "description": "Title for describing the series"
35
    },
36
    "copyrightdate": {
37
      "type": ["string", "null"],
38
      "description": "publication or copyright date from the MARC record"
39
    },
40
    "timestamp": {
41
      "type": "string",
42
      "description": "date and time this record was last touched"
43
    },
44
    "datecreated": {
45
      "type": "string",
46
      "description": "the date this record was added to Koha"
47
    },
48
    "abstract": {
49
      "type": ["string", "null"],
50
      "description": "summary from the MARC record (520$a in MARC21)"
51
    },
52
    "items": {
53
      "type": "array",
54
      "items": {
55
        "type": "object",
56
        "properties": {
57
          "itemnumber": {
58
            "type": "string",
59
            "description": "internal item identifier"
60
          }
61
        }
62
      }
63
    }
64
  }
65
}
(-)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/editAccountlineBody.json (+17 lines)
Line 0 Link Here
1
{
2
    "type": "object",
3
        "properties": {
4
            "amount": {
5
                "description": "Amount"
6
            },
7
            "amountoutstanding": {
8
                "description": "Amount outstanding"
9
            },
10
            "note": {
11
                "description": "Accountline note"
12
            },
13
            "meansofpayment": {
14
                "description": "Means of payment"
15
            }
16
      }
17
}
(-)a/api/v1/definitions/index.json (+12 lines)
Lines 1-6 Link Here
1
{
1
{
2
    "availability": { "$ref": "availability.json" },
3
    "availabilities": { "$ref": "availabilities.json" },
4
    "amountpaid": { "$ref": "amountpaid.json" },
5
    "accountline": { "$ref": "accountline.json" },
6
    "editAccountlineBody": { "$ref": "editAccountlineBody.json" },
7
    "partialpayAccountlineBody": { "$ref": "partialpayAccountlineBody.json" },
2
    "patron": { "$ref": "patron.json" },
8
    "patron": { "$ref": "patron.json" },
9
    "checkouts": { "$ref": "checkouts.json" },
10
    "checkout": { "$ref": "checkout.json" },
3
    "holds": { "$ref": "holds.json" },
11
    "holds": { "$ref": "holds.json" },
4
    "hold": { "$ref": "hold.json" },
12
    "hold": { "$ref": "hold.json" },
13
    "libraries": { "$ref": "libraries.json" },
14
    "library": { "$ref": "library.json" },
15
    "item": { "$ref": "item.json" },
16
    "biblio": { "$ref": "biblio.json" },
5
    "error": { "$ref": "error.json" }
17
    "error": { "$ref": "error.json" }
6
}
18
}
(-)a/api/v1/definitions/item.json (+177 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "itemnumber": {
5
      "type": "string",
6
      "description": "internally assigned item identifier"
7
    },
8
    "biblionumber": {
9
      "type": "string",
10
      "description": "internally assigned biblio identifier"
11
    },
12
    "biblioitemnumber": {
13
      "type": "string",
14
      "description": "internally assigned biblio item identifier"
15
    },
16
    "barcode": {
17
      "type": ["string", "null"],
18
      "description": "item barcode"
19
    },
20
    "dateaccessioned": {
21
      "type": ["string", "null"],
22
      "description": "date the item was acquired or added to Koha"
23
    },
24
    "booksellerid": {
25
      "type": ["string", "null"],
26
      "description": "where the item was purchased"
27
    },
28
    "homebranch": {
29
      "type": ["string", "null"],
30
      "description": "library that owns this item"
31
    },
32
    "price": {
33
      "type": ["string", "null"],
34
      "description": "purchase price"
35
    },
36
    "replacementprice": {
37
      "type": ["string", "null"],
38
      "description": "cost the library charges to replace the item if it has been marked lost"
39
    },
40
    "replacementpricedate": {
41
      "type": ["string", "null"],
42
      "description": "the date the price is effective from"
43
    },
44
    "datelastborrowed": {
45
      "type": ["string", "null"],
46
      "description": "the date the item was last checked out/issued"
47
    },
48
    "datelastseen": {
49
      "type": ["string", "null"],
50
      "description": "the date the item was last see (usually the last time the barcode was scanned or inventory was done)"
51
    },
52
    "stack": {
53
      "type": ["string", "null"],
54
      "description": "?"
55
    },
56
    "notforloan": {
57
      "type": "string",
58
      "description": "authorized value defining why this item is not for loan"
59
    },
60
    "damaged": {
61
      "type": "string",
62
      "description": "authorized value defining this item as damaged"
63
    },
64
    "itemlost": {
65
      "type": "string",
66
      "description": "authorized value defining this item as lost"
67
    },
68
    "itemlost_on": {
69
      "type": ["string", "null"],
70
      "description": "the date and time an item was last marked as lost, NULL if not lost"
71
    },
72
    "withdrawn": {
73
      "type": "string",
74
      "description": "authorized value defining this item as withdrawn"
75
    },
76
    "withdrawn_on": {
77
      "type": ["string", "null"],
78
      "description": "the date and time an item was last marked as withdrawn, NULL if not withdrawn"
79
    },
80
    "itemcallnumber": {
81
      "type": ["string", "null"],
82
      "description": "call number for this item"
83
    },
84
    "coded_location_qualifier": {
85
      "type": ["string", "null"],
86
      "description": "coded location qualifier"
87
    },
88
    "issues": {
89
      "type": ["string", "null"],
90
      "description": "number of times this item has been checked out/issued"
91
    },
92
    "renewals": {
93
      "type": ["string", "null"],
94
      "description": "number of times this item has been renewed"
95
    },
96
    "reserves": {
97
      "type": ["string", "null"],
98
      "description": "number of times this item has been placed on hold/reserved"
99
    },
100
    "restricted": {
101
      "type": ["string", "null"],
102
      "description": "authorized value defining use restrictions for this item"
103
    },
104
    "itemnotes": {
105
      "type": ["string", "null"],
106
      "description": "public notes on this item"
107
    },
108
    "itemnotes_nonpublic": {
109
      "type": ["string", "null"],
110
      "description": "non-public notes on this item"
111
    },
112
    "holdingbranch": {
113
      "type": ["string", "null"],
114
      "description": "library that is currently in possession item"
115
    },
116
    "paidfor": {
117
      "type": ["string", "null"],
118
      "description": "?"
119
    },
120
    "timestamp": {
121
      "type": "string",
122
      "description": "date and time this item was last altered"
123
    },
124
    "location": {
125
      "type": ["string", "null"],
126
      "description": "authorized value for the shelving location for this item"
127
    },
128
    "permanent_location": {
129
      "type": ["string", "null"],
130
      "description": "linked to the CART and PROC temporary locations feature, stores the permanent shelving location"
131
    },
132
    "onloan": {
133
      "type": ["string", "null"],
134
      "description": "defines if item is checked out (NULL for not checked out, and checkout date for checked out)"
135
    },
136
    "cn_source": {
137
      "type": ["string", "null"],
138
      "description": "classification source used on this item"
139
    },
140
    "cn_sort": {
141
      "type": ["string", "null"],
142
      "description": "?"
143
    },
144
    "ccode": {
145
      "type": ["string", "null"],
146
      "description": "authorized value for the collection code associated with this item"
147
    },
148
    "materials": {
149
      "type": ["string", "null"],
150
      "description": "materials specified"
151
    },
152
    "uri": {
153
      "type": ["string", "null"],
154
      "description": "URL for the item"
155
    },
156
    "itype": {
157
      "type": ["string", "null"],
158
      "description": "itemtype defining the type for this item"
159
    },
160
    "more_subfields_xml": {
161
      "type": ["string", "null"],
162
      "description": "additional 952 subfields in XML format"
163
    },
164
    "enumchron": {
165
      "type": ["string", "null"],
166
      "description": "serial enumeration/chronology for the item"
167
    },
168
    "copynumber": {
169
      "type": ["string", "null"],
170
      "description": "copy number"
171
    },
172
    "stocknumber": {
173
      "type": ["string", "null"],
174
      "description": "inventory number"
175
    }
176
  }
177
}
(-)a/api/v1/definitions/libraries.json (+4 lines)
Line 0 Link Here
1
{
2
    "type": "array",
3
    "items": { "$ref": "library.json" }
4
}
(-)a/api/v1/definitions/library.json (+77 lines)
Line 0 Link Here
1
{
2
    "type": "object",
3
    "properties": {
4
        "branchcode": {
5
            "type": "string",
6
            "description": "Internal library identifier"
7
        },
8
        "branchname": {
9
            "type": "string",
10
            "description": "Printable name of library"
11
        },
12
        "branchaddress1": {
13
            "type": ["string", "null"],
14
            "description": "the first address line of the library"
15
        },
16
        "branchaddress2": {
17
            "type": ["string", "null"],
18
            "description": "the second address line of the library"
19
        },
20
        "branchaddress3": {
21
            "type": ["string", "null"],
22
            "description": "the third address line of the library"
23
        },
24
        "branchzip": {
25
            "type": ["string", "null"],
26
            "description": "the zip or postal code of the library"
27
        },
28
        "branchcity": {
29
            "type": ["string", "null"],
30
            "description": "the city or province of the library"
31
        },
32
        "branchstate": {
33
            "type": ["string", "null"],
34
            "description": "the reqional state of the library"
35
        },
36
        "branchcountry": {
37
            "type": ["string", "null"],
38
            "description": "the county of the library"
39
        },
40
        "branchphone": {
41
            "type": ["string", "null"],
42
            "description": "the primary phone of the library"
43
        },
44
        "branchfax": {
45
            "type": ["string", "null"],
46
            "description": "the fax number of the library"
47
        },
48
        "branchemail": {
49
            "type": ["string", "null"],
50
            "description": "the primary email address of the library"
51
        },
52
        "branchreplyto": {
53
            "type": ["string", "null"],
54
            "description": "the email to be used as a Reply-To"
55
        },
56
        "branchreturnpath": {
57
            "type": ["string", "null"],
58
            "description": "the email to be used as Return-Path"
59
        },
60
        "branchurl": {
61
            "type": ["string", "null"],
62
            "description": "the URL for your library or branch's website"
63
        },
64
        "branchip": {
65
            "type": ["string", "null"],
66
            "description": "the IP address for your library or branch"
67
        },
68
        "branchnotes": {
69
            "type": ["string", "null"],
70
            "description": "notes related to your library or branch"
71
        },
72
        "opac_info": {
73
            "type": ["string", "null"],
74
            "description": "HTML that displays in OPAC"
75
        }
76
    }
77
}
(-)a/api/v1/definitions/partialpayAccountlineBody.json (+11 lines)
Line 0 Link Here
1
{
2
    "type": "object",
3
        "properties": {
4
            "amount": {
5
                "description": "Amount to pay"
6
            },
7
            "note": {
8
                "description": "Payment note"
9
            }
10
      }
11
}
(-)a/api/v1/swagger.json (+648 lines)
Lines 14-19 Link Here
14
  },
14
  },
15
  "basePath": "/api/v1",
15
  "basePath": "/api/v1",
16
  "paths": {
16
  "paths": {
17
    "/availability/items": {
18
      "get": {
19
        "operationId": "itemsAvailability",
20
        "tags": ["items", "availability"],
21
        "parameters": [
22
          { "$ref": "#/parameters/itemnumbersQueryParam" },
23
          { "$ref": "#/parameters/biblionumbersQueryParam" }
24
        ],
25
        "consumes": ["application/json"],
26
        "produces": ["application/json"],
27
        "responses": {
28
          "200": {
29
            "description": "Availability information on item(s)",
30
            "schema": {
31
              "$ref": "#/definitions/availabilities"
32
            }
33
          },
34
          "400": {
35
            "description": "Missing or wrong parameters",
36
            "schema": { "$ref": "#/definitions/error" }
37
          },
38
          "404": {
39
            "description": "No item(s) found",
40
            "schema": { "$ref": "#/definitions/error" }
41
          }
42
        }
43
      }
44
    },
17
    "/patrons": {
45
    "/patrons": {
18
      "get": {
46
      "get": {
19
        "operationId": "listPatrons",
47
        "operationId": "listPatrons",
Lines 38-43 Link Here
38
            }
66
            }
39
          }
67
          }
40
        }
68
        }
69
      },
70
      "post": {
71
        "operationId": "addPatron",
72
        "tags": ["patrons"],
73
        "parameters": [{
74
          "name": "body",
75
          "in": "body",
76
          "description": "A JSON object containing information about the new patron",
77
          "required": true,
78
          "schema": {
79
            "$ref": "#/definitions/patron"
80
          }
81
        }],
82
        "consumes": ["application/json"],
83
        "produces": ["application/json"],
84
        "responses": {
85
          "201": {
86
            "description": "A successfully created patron",
87
            "schema": {
88
              "items": {
89
                "$ref": "#/definitions/patron"
90
              }
91
            }
92
          },
93
          "403": {
94
            "description": "Access forbidden",
95
            "schema": {
96
              "$ref": "#/definitions/error"
97
            }
98
          },
99
          "404": {
100
            "description": "Resource not found",
101
            "schema": {
102
              "$ref": "#/definitions/error"
103
            }
104
          },
105
          "409": {
106
            "description": "Conflict in creating resource",
107
            "schema": {
108
              "$ref": "#/definitions/error"
109
            }
110
          },
111
          "500": {
112
            "description": "Internal error",
113
            "schema": {
114
              "$ref": "#/definitions/error"
115
            }
116
          }
117
        }
41
      }
118
      }
42
    },
119
    },
43
    "/patrons/{borrowernumber}": {
120
    "/patrons/{borrowernumber}": {
Lines 72-77 Link Here
72
            }
149
            }
73
          }
150
          }
74
        }
151
        }
152
      },
153
      "put": {
154
        "operationId": "editPatron",
155
        "tags": ["patrons"],
156
        "parameters": [
157
          { "$ref": "#/parameters/borrowernumberPathParam" },
158
          {
159
            "name": "body",
160
            "in": "body",
161
            "description": "A JSON object containing new information about existing patron",
162
            "required": true,
163
            "schema": {
164
              "$ref": "#/definitions/patron"
165
            }
166
          }
167
        ],
168
        "consumes": ["application/json"],
169
        "produces": ["application/json"],
170
        "responses": {
171
          "200": {
172
            "description": "A successfully updated patron",
173
            "schema": {
174
              "items": {
175
                "$ref": "#/definitions/patron"
176
              }
177
            }
178
          },
179
          "204": {
180
            "description": "No Content",
181
            "schema": {
182
              "type": "object"
183
            }
184
          },
185
          "403": {
186
            "description": "Access forbidden",
187
            "schema": {
188
              "$ref": "#/definitions/error"
189
            }
190
          },
191
          "404": {
192
            "description": "Resource not found",
193
            "schema": {
194
              "$ref": "#/definitions/error"
195
            }
196
          },
197
          "409": {
198
            "description": "Conflict in updating resource",
199
            "schema": {
200
              "$ref": "#/definitions/error"
201
            }
202
          },
203
          "500": {
204
            "description": "Internal error",
205
            "schema": {
206
              "$ref": "#/definitions/error"
207
            }
208
          }
209
        }
210
      },
211
      "delete": {
212
        "operationId": "deletePatron",
213
        "tags": ["patrons"],
214
        "parameters": [
215
          { "$ref": "#/parameters/borrowernumberPathParam" }
216
        ],
217
        "produces": ["application/json"],
218
        "responses": {
219
          "200": {
220
            "description": "Patron deleted successfully",
221
            "schema": {
222
              "type": "object"
223
            }
224
          },
225
          "400": {
226
            "description": "Patron deletion failed",
227
            "schema": { "$ref": "#/definitions/error" }
228
          },
229
          "403": {
230
            "description": "Access forbidden",
231
            "schema": {
232
              "$ref": "#/definitions/error"
233
            }
234
          },
235
          "404": {
236
            "description": "Patron not found",
237
            "schema": { "$ref": "#/definitions/error" }
238
          }
239
        }
75
      }
240
      }
76
    },
241
    },
77
    "/holds": {
242
    "/holds": {
Lines 332-343 Link Here
332
          }
497
          }
333
        }
498
        }
334
      }
499
      }
500
    },
501
    "/accountlines": {
502
      "get": {
503
        "operationId": "listAccountlines",
504
        "tags": ["accountlines"],
505
        "produces": [
506
          "application/json"
507
        ],
508
        "responses": {
509
          "200": {
510
            "description": "A list of accountlines",
511
            "schema": {
512
              "type": "array",
513
              "items": {
514
                "$ref": "#/definitions/accountline"
515
              }
516
            }
517
          },
518
          "403": {
519
            "description": "Access forbidden",
520
            "schema": {
521
              "$ref": "#/definitions/error"
522
            }
523
          }
524
        }
525
      }
526
    },
527
    "/libraries": {
528
      "get": {
529
        "operationId": "listLibrary",
530
        "tags": ["libraries"],
531
        "produces": [
532
          "application/json"
533
        ],
534
        "responses": {
535
          "200": {
536
            "description": "A list of libraries",
537
            "schema": {
538
              "$ref": "#/definitions/libraries"
539
            }
540
          }
541
        }
542
      }
543
    },
544
    "/libraries/{branchcode}": {
545
      "get": {
546
        "operationId": "getLibrary",
547
        "tags": ["libraries"],
548
        "parameters": [
549
          { "$ref": "#/parameters/branchcodePathParam" }
550
        ],
551
        "produces": [
552
          "application/json"
553
        ],
554
        "responses": {
555
          "200": {
556
            "description": "A library",
557
            "schema": {
558
              "$ref": "#/definitions/library"
559
            }
560
          },
561
          "404": {
562
            "description": "Library not found",
563
            "schema": {
564
              "$ref": "#/definitions/error"
565
            }
566
          }
567
        }
568
      }
569
    },
570
    "/checkouts": {
571
      "get": {
572
        "operationId": "listCheckouts",
573
        "tags": ["borrowers", "checkouts"],
574
        "parameters": [
575
          {
576
            "name": "borrowernumber",
577
            "in": "query",
578
            "description": "Internal patron identifier",
579
            "required": false,
580
            "type": "integer"
581
          }
582
        ],
583
        "produces": [
584
          "application/json"
585
        ],
586
        "responses": {
587
          "200": {
588
            "description": "A list of checkouts",
589
            "schema": {
590
              "$ref": "#/definitions/checkouts"
591
            }
592
          },
593
          "403": {
594
            "description": "Access forbidden",
595
            "schema": { "$ref": "#/definitions/error" }
596
          },
597
          "404": {
598
            "description": "Borrower not found",
599
            "schema": {
600
              "$ref": "#/definitions/error"
601
            }
602
          }
603
        }
604
      }
605
    },
606
    "/checkouts/{checkout_id}": {
607
      "get": {
608
        "operationId": "getCheckout",
609
        "tags": ["borrowers", "checkouts"],
610
        "parameters": [
611
          {
612
            "name": "checkout_id",
613
            "in": "path",
614
            "description": "Internal checkout identifier",
615
            "required": true,
616
            "type": "integer"
617
          }
618
        ],
619
        "produces": ["application/json"],
620
        "responses": {
621
          "200": {
622
            "description": "Updated borrower's checkout",
623
            "schema": { "$ref": "#/definitions/checkout" }
624
          },
625
          "403": {
626
            "description": "Access forbidden",
627
            "schema": { "$ref": "#/definitions/error" }
628
          },
629
          "404": {
630
            "description": "Checkout not found",
631
            "schema": { "$ref": "#/definitions/error" }
632
          }
633
        }
634
      },
635
      "put": {
636
        "operationId": "renewCheckout",
637
        "tags": ["borrowers", "checkouts"],
638
        "parameters": [
639
          {
640
            "name": "checkout_id",
641
            "in": "path",
642
            "description": "Internal checkout identifier",
643
            "required": true,
644
            "type": "integer"
645
          }
646
        ],
647
        "produces": ["application/json"],
648
        "responses": {
649
          "200": {
650
            "description": "Updated borrower's checkout",
651
            "schema": { "$ref": "#/definitions/checkout" }
652
          },
653
          "403": {
654
            "description": "Cannot renew checkout",
655
            "schema": { "$ref": "#/definitions/error" }
656
          },
657
          "404": {
658
            "description": "Checkout not found",
659
            "schema": { "$ref": "#/definitions/error" }
660
          }
661
        }
662
      }
663
    },
664
    "/checkouts/history": {
665
      "get": {
666
        "operationId": "listhistoryCheckouts",
667
        "tags": ["borrowers", "checkouts"],
668
        "parameters": [
669
          {
670
            "name": "borrowernumber",
671
            "in": "query",
672
            "description": "Internal patron identifier",
673
            "required": false,
674
            "type": "integer"
675
          }
676
        ],
677
        "produces": [
678
          "application/json"
679
        ],
680
        "responses": {
681
          "200": {
682
            "description": "A list of checkouts history",
683
            "schema": {
684
              "$ref": "#/definitions/checkouts"
685
            }
686
          },
687
          "403": {
688
            "description": "Access forbidden",
689
            "schema": { "$ref": "#/definitions/error" }
690
          },
691
          "404": {
692
            "description": "Borrower not found",
693
            "schema": {
694
              "$ref": "#/definitions/error"
695
            }
696
          }
697
        }
698
      }
699
    },
700
    "/checkouts/history/{checkout_id}": {
701
      "get": {
702
        "operationId": "gethistoryCheckout",
703
        "tags": ["borrowers", "checkouts"],
704
        "parameters": [
705
          {
706
            "name": "checkout_id",
707
            "in": "path",
708
            "description": "Internal checkout identifier",
709
            "required": true,
710
            "type": "integer"
711
          }
712
        ],
713
        "produces": ["application/json"],
714
        "responses": {
715
          "200": {
716
            "description": "Got borrower's checkout",
717
            "schema": { "$ref": "#/definitions/checkout" }
718
          },
719
          "403": {
720
            "description": "Access forbidden",
721
            "schema": { "$ref": "#/definitions/error" }
722
          },
723
          "404": {
724
            "description": "Checkout not found",
725
            "schema": { "$ref": "#/definitions/error" }
726
          }
727
        }
728
      }
729
    },
730
    "/items/{itemnumber}": {
731
      "get": {
732
        "operationId": "getItem",
733
        "tags": ["items"],
734
        "parameters": [
735
          { "$ref": "#/parameters/itemnumberPathParam" }
736
        ],
737
        "consumes": ["application/json"],
738
        "produces": ["application/json"],
739
        "responses": {
740
          "200": {
741
            "description": "An item",
742
            "schema": { "$ref": "#/definitions/item" }
743
          },
744
          "400": {
745
            "description": "Missing or wrong parameters",
746
            "schema": { "$ref": "#/definitions/error" }
747
          },
748
          "404": {
749
            "description": "Item not found",
750
            "schema": { "$ref": "#/definitions/error" }
751
          }
752
        }
753
      }
754
    },
755
    "/biblios/{biblionumber}": {
756
      "get": {
757
        "operationId": "getBiblio",
758
        "tags": ["biblios"],
759
        "parameters": [
760
          { "$ref": "#/parameters/biblionumberPathParam" }
761
        ],
762
        "consumes": ["application/json"],
763
        "produces": ["application/json"],
764
        "responses": {
765
          "200": {
766
            "description": "An biblio",
767
            "schema": { "$ref": "#/definitions/biblio" }
768
          },
769
          "400": {
770
            "description": "Missing or wrong parameters",
771
            "schema": { "$ref": "#/definitions/error" }
772
          },
773
          "404": {
774
            "description": "Biblio not found",
775
            "schema": { "$ref": "#/definitions/error" }
776
          }
777
        }
778
      }
779
    },
780
    "/accountlines/{accountlines_id}": {
781
      "put": {
782
        "operationId": "editAccountlines",
783
        "tags": ["accountlines"],
784
        "produces": [
785
          "application/json"
786
        ],
787
        "parameters": [
788
          { "$ref": "#/parameters/accountlinesIdPathParam" },
789
          {
790
            "name": "body",
791
            "in": "body",
792
            "description": "A JSON object containing fields to modify",
793
            "required": true,
794
            "schema": { "$ref": "#/definitions/editAccountlineBody" }
795
          }
796
        ],
797
        "consumes": ["application/json"],
798
        "produces": ["application/json"],
799
        "responses": {
800
          "200": {
801
            "description": "Updated accountline",
802
            "schema": { "$ref": "#/definitions/accountline" }
803
          },
804
          "400": {
805
            "description": "Missing or wrong parameters",
806
            "schema": { "$ref": "#/definitions/error" }
807
          },
808
          "403": {
809
            "description": "Access forbidden",
810
            "schema": {
811
              "$ref": "#/definitions/error"
812
            }
813
          },
814
          "404": {
815
            "description": "Accountline not found",
816
            "schema": { "$ref": "#/definitions/error" }
817
          }
818
        }
819
      }
820
    },
821
    "/accountlines/{accountlines_id}/payment": {
822
      "put": {
823
        "operationId": "payAccountlines",
824
        "tags": ["accountlines"],
825
        "produces": [
826
          "application/json"
827
        ],
828
        "parameters": [
829
          { "$ref": "#/parameters/accountlinesIdPathParam" }
830
        ],
831
        "produces": ["application/json"],
832
        "responses": {
833
          "200": {
834
            "description": "Paid accountline",
835
            "schema": { "$ref": "#/definitions/accountline" }
836
          },
837
          "400": {
838
            "description": "Missing or wrong parameters",
839
            "schema": { "$ref": "#/definitions/error" }
840
          },
841
          "403": {
842
            "description": "Access forbidden",
843
            "schema": {
844
              "$ref": "#/definitions/error"
845
            }
846
          },
847
          "404": {
848
            "description": "Accountline not found",
849
            "schema": { "$ref": "#/definitions/error" }
850
          }
851
        }
852
      }
853
    },
854
    "/accountlines/{accountlines_id}/partialpayment": {
855
      "put": {
856
        "operationId": "partialpayAccountlines",
857
        "tags": ["accountlines"],
858
        "produces": [
859
          "application/json"
860
        ],
861
        "parameters": [
862
          { "$ref": "#/parameters/accountlinesIdPathParam" },
863
          {
864
            "name": "body",
865
            "in": "body",
866
            "description": "A JSON object containing fields to modify",
867
            "required": true,
868
            "schema": { "$ref": "#/definitions/partialpayAccountlineBody" }
869
          }
870
        ],
871
        "consumes": ["application/json"],
872
        "produces": ["application/json"],
873
        "responses": {
874
          "200": {
875
            "description": "Paid accountline",
876
            "schema": { "$ref": "#/definitions/accountline" }
877
          },
878
          "400": {
879
            "description": "Missing or wrong parameters",
880
            "schema": { "$ref": "#/definitions/error" }
881
          },
882
          "403": {
883
            "description": "Access forbidden",
884
            "schema": {
885
              "$ref": "#/definitions/error"
886
            }
887
          },
888
          "404": {
889
            "description": "Accountline not found",
890
            "schema": { "$ref": "#/definitions/error" }
891
          }
892
        }
893
      }
894
    },
895
    "/accountlines/{borrowernumber}/amountpayment": {
896
      "put": {
897
        "operationId": "payamountAccountlines",
898
        "tags": ["accountlines"],
899
        "produces": [
900
          "application/json"
901
        ],
902
        "parameters": [
903
          { "$ref": "#/parameters/borrowernumberPathParam" },
904
          {
905
            "name": "body",
906
            "in": "body",
907
            "description": "A JSON object containing fields to modify",
908
            "required": true,
909
            "schema": { "$ref": "#/definitions/partialpayAccountlineBody" }
910
          }
911
        ],
912
        "consumes": ["application/json"],
913
        "produces": ["application/json"],
914
        "responses": {
915
          "200": {
916
            "description": "Amount paid",
917
            "schema": { "$ref": "#/definitions/amountpaid" }
918
          },
919
          "400": {
920
            "description": "Missing or wrong parameters",
921
            "schema": { "$ref": "#/definitions/error" }
922
          },
923
          "403": {
924
            "description": "Access forbidden",
925
            "schema": {
926
              "$ref": "#/definitions/error"
927
            }
928
          },
929
          "404": {
930
            "description": "Borrower not found",
931
            "schema": { "$ref": "#/definitions/error" }
932
          }
933
        }
934
      }
335
    }
935
    }
336
  },
936
  },
337
  "definitions": {
937
  "definitions": {
338
    "$ref": "./definitions/index.json"
938
    "$ref": "./definitions/index.json"
339
  },
939
  },
340
  "parameters": {
940
  "parameters": {
941
    "biblionumbersQueryParam": {
942
      "name": "biblionumber",
943
      "in": "query",
944
      "description": "Internal biblios identifier",
945
      "type": "array",
946
      "items": {
947
        "type": "integer"
948
      },
949
      "collectionFormat": "ssv"
950
    },
341
    "borrowernumberPathParam": {
951
    "borrowernumberPathParam": {
342
      "name": "borrowernumber",
952
      "name": "borrowernumber",
343
      "in": "path",
953
      "in": "path",
Lines 351-356 Link Here
351
      "description": "Internal hold identifier",
961
      "description": "Internal hold identifier",
352
      "required": true,
962
      "required": true,
353
      "type": "integer"
963
      "type": "integer"
964
    },
965
    "branchcodePathParam": {
966
      "name": "branchcode",
967
      "in": "path",
968
      "description": "Internal library identifier",
969
      "required": true,
970
      "type": "string"
971
    },
972
    "itemnumberPathParam": {
973
      "name": "itemnumber",
974
      "in": "path",
975
      "description": "Internal item identifier",
976
      "required": true,
977
      "type": "integer"
978
    },
979
    "biblionumberPathParam": {
980
        "name": "biblionumber",
981
        "in": "path",
982
        "description": "Internal biblio identifier",
983
        "required": true,
984
        "type": "integer"
985
    },
986
    "itemnumbersQueryParam": {
987
      "name": "itemnumber",
988
      "in": "query",
989
      "description": "Internal items identifier",
990
      "type": "array",
991
      "items": {
992
        "type": "integer"
993
      },
994
      "collectionFormat": "ssv"
995
    },
996
    "accountlinesIdPathParam": {
997
      "name": "accountlines_id",
998
      "in": "path",
999
      "description": "Internal accountline identifier",
1000
      "required": true,
1001
      "type": "integer"
354
    }
1002
    }
355
  }
1003
  }
356
}
1004
}
(-)a/t/Koha/Item/Availability.t (+71 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright KohaSuomi 2016
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Test::More tests => 16;
22
23
use_ok('Koha::Item::Availability');
24
25
my $availability = Koha::Item::Availability->new->set_available;
26
27
is($availability->{available}, 1, "Available");
28
$availability->set_needs_confirmation;
29
is($availability->{availability_needs_confirmation}, 1, "Needs confirmation");
30
$availability->set_unavailable;
31
is($availability->{available}, 0, "Not available");
32
33
$availability->add_description("such available");
34
$availability->add_description("wow");
35
$availability->add_description("wow");
36
37
ok($availability->has_description("wow"), "Found description 'wow'");
38
ok($availability->has_description(["wow", "such available"]),
39
   "Found description 'wow' and 'such available'");
40
is($availability->has_description(["wow", "much not found"]), 0,
41
   "Didn't find 'wow' and 'much not found'");
42
is($availability->{description}[0], "such available",
43
   "Found correct description in correct index 1/4");
44
is($availability->{description}[1], "wow",
45
   "Found correct description in correct index 2/2");
46
47
$availability->add_description(["much description", "very doge"]);
48
is($availability->{description}[2], "much description",
49
   "Found correct description in correct index 3/4");
50
is($availability->{description}[3], "very doge",
51
   "Found correct description in correct index 4/4");
52
53
$availability->del_description("wow");
54
is($availability->{description}[1], "much description",
55
   "Found description from correct index after del");
56
$availability->del_description(["very doge", "such available"]);
57
is($availability->{description}[0], "much description",
58
   "Found description from correct index after del");
59
60
61
my $availability_clone = $availability;
62
$availability->set_unavailable;
63
is($availability_clone->{available}, $availability->{available},
64
   "Availability_clone points to availability");
65
$availability_clone = $availability->clone;
66
$availability->set_available;
67
isnt($availability_clone->{available}, $availability->{available},
68
     "Availability_clone was cloned and no longer has same availability status");
69
70
$availability->reset;
71
is($availability->{available}, undef, "Availability reset");
(-)a/t/db_dependent/Items.t (-1 / +110 lines)
Lines 20-26 use Modern::Perl; Link Here
20
20
21
use MARC::Record;
21
use MARC::Record;
22
use C4::Biblio;
22
use C4::Biblio;
23
use C4::Circulation;
24
use C4::Reserves;
23
use Koha::Database;
25
use Koha::Database;
26
use Koha::Hold;
27
use Koha::Issue;
28
use Koha::Item::Availability;
24
use Koha::Library;
29
use Koha::Library;
25
30
26
use t::lib::Mocks;
31
use t::lib::Mocks;
Lines 432-438 subtest 'SearchItems test' => sub { Link Here
432
437
433
subtest 'Koha::Item(s) tests' => sub {
438
subtest 'Koha::Item(s) tests' => sub {
434
439
435
    plan tests => 5;
440
    plan tests => 40;
436
441
437
    $schema->storage->txn_begin();
442
    $schema->storage->txn_begin();
438
443
Lines 443-448 subtest 'Koha::Item(s) tests' => sub { Link Here
443
    my $library2 = $builder->build({
448
    my $library2 = $builder->build({
444
        source => 'Branch',
449
        source => 'Branch',
445
    });
450
    });
451
    my $borrower = $builder->build({
452
        source => 'Borrower',
453
    });
454
    my $itemtype = $builder->build({
455
        source => 'Itemtype',
456
        value => {
457
            notforloan => 1
458
        }
459
    });
446
460
447
    # Create a biblio and item for testing
461
    # Create a biblio and item for testing
448
    t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
462
    t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
Lines 461-466 subtest 'Koha::Item(s) tests' => sub { Link Here
461
    is( ref($holdingbranch), 'Koha::Library', "Got Koha::Library from holding_branch method" );
475
    is( ref($holdingbranch), 'Koha::Library', "Got Koha::Library from holding_branch method" );
462
    is( $holdingbranch->branchcode(), $library2->{branchcode}, "Home branch code matches holdingbranch" );
476
    is( $holdingbranch->branchcode(), $library2->{branchcode}, "Home branch code matches holdingbranch" );
463
477
478
    # Availability tests
479
    my $availability = $item->availability_for_checkout();
480
    is (ref($availability), 'Koha::Item::Availability', 'Got Koha::Item::Availability');
481
    is( $availability->{available}, 1, "Item is available" );
482
    $availability = $item->availability_for_local_use();
483
    is( $availability->{available}, 1, "Item is available for local use" );
484
    t::lib::Mocks::mock_preference('OnSiteCheckouts', 0);
485
    $availability = $item->availability_for_onsite_checkout();
486
    is( $availability->{available}, 0, "Not available for on-site checkouts" );
487
    is( $availability->{description}[0], "onsite_checkouts_disabled", "Availability description is 'onsite_checkouts_disabled'" );
488
    t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
489
    $availability = $item->availability_for_onsite_checkout();
490
    is( $availability->{available}, 1, "Available for on-site checkouts" );
491
492
    $item->set({ onloan => "", damaged => 1 })->store();
493
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 0);
494
    $availability = $item->availability_for_checkout();
495
    is( $availability->{available}, 0, "Damaged item unavailable" );
496
    is( $availability->{description}[0], "damaged", "Availability description is 'damaged'" );
497
    $availability = $item->availability_for_local_use();
498
    is( $availability->{available}, 0, "Item is not available for local use" );
499
    $availability = $item->availability_for_onsite_checkout();
500
    is( $availability->{available}, 0, "Item is not available for on-site checkouts" );
501
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1);
502
    $availability = $item->availability_for_checkout();
503
    is( $availability->{available}, 1, "Damaged item available" );
504
    is( $availability->{description}[0], "damaged", "Availability description is 'damaged'" );
505
    $availability = $item->availability_for_local_use();
506
    is( $availability->{available}, 1, "Item is available for local use" );
507
    $availability = $item->availability_for_onsite_checkout();
508
    is( $availability->{available}, 1, "Item is available for on-site checkouts" );
509
510
    $item->set({ damaged => 0, withdrawn => 1 })->store();
511
    $availability = $item->availability_for_checkout();
512
    is( $availability->{available}, 0, "Item is not available" );
513
    is( $availability->{description}[0], "withdrawn", "Availability description is 'withdrawn'" );
514
515
    $item->set({ withdrawn => 0, itemlost => 1 })->store();
516
    $availability = $item->availability_for_checkout();
517
    is( $availability->{available}, 0, "Item is not available" );
518
    is( $availability->{description}[0], "itemlost", "Availability description is 'itemlost'" );
519
520
    $item->set({ itemlost => 0, restricted => 1 })->store();
521
    $availability = $item->availability_for_checkout();
522
    is( $availability->{available}, 0, "Item is not available" );
523
    is( $availability->{description}[0], "restricted", "Availability description is 'restricted'" );
524
525
    $item->set({ restricted => 0, notforloan => 1 })->store();
526
    $availability = $item->availability_for_checkout();
527
    is( $availability->{available}, 0, "Item is not available" );
528
    is( $availability->{description}[0], "notforloan", "Availability description is 'notforloan'" );
529
    $availability = $item->availability_for_local_use();
530
    is( $availability->{available}, 1, "Item is available for local use" );
531
    $availability = $item->availability_for_onsite_checkout();
532
    is( $availability->{available}, C4::Context->preference('OnSiteCheckouts'), "Good availability for on-site checkouts" );
533
534
    $item->set({ notforloan => 0, itype => $itemtype->{itemtype} })->store();
535
    $availability = $item->availability_for_checkout();
536
    is( $availability->{available}, 0, "Item is not available" );
537
    is( $availability->{description}[0], "notforloan", "Availability description is 'notforloan' (itemtype)" );
538
    $availability = $item->availability_for_local_use();
539
    is( $availability->{available}, 1, "Item is available for local use" );
540
    $availability = $item->availability_for_onsite_checkout();
541
    is( $availability->{available}, C4::Context->preference('OnSiteCheckouts'), "Good availability for on-site checkouts" );
542
543
    $item->set({ itype => undef, barcode => "test" })->store();
544
    my $reserve = Koha::Hold->new(
545
        {
546
            biblionumber   => $item->biblionumber,
547
            itemnumber     => $item->itemnumber,
548
            waitingdate    => '2000-01-01',
549
            borrowernumber => $borrower->{borrowernumber},
550
            branchcode     => $item->homebranch,
551
            suspend        => 0,
552
        }
553
    )->store();
554
    $availability = $item->availability_for_checkout();
555
    is( $availability->{available}, 0, "Item is not available" );
556
    is( $availability->{description}[0], "reserved", "Availability description is 'reserved'" );
557
    $availability = $item->availability_for_reserve();
558
    is( $availability->{available}, 1, "Item is available for reserve" );
559
    CancelReserve({ reserve_id => $reserve->reserve_id });
560
561
    $availability = $item->availability_for_checkout();
562
    is( $availability->{available}, 1, "Item is available" );
563
564
    my $module = new Test::MockModule('C4::Context');
565
    $module->mock( 'userenv', sub { { branch => $borrower->{branchcode} } } );
566
    my $issue = AddIssue($borrower, $item->barcode, undef, 1);
567
    $item = Koha::Items->find($item->itemnumber); # refresh item
568
    $availability = $item->availability_for_checkout();
569
    is( $availability->{available}, 0, "Item is not available" );
570
    is( $availability->{description}[0], "onloan", "Availability description is 'onloan'" );
571
    is( $availability->{expected_available}, $issue->date_due, "Expected to be available '".$issue->date_due."'");
572
464
    $schema->storage->txn_rollback;
573
    $schema->storage->txn_rollback;
465
};
574
};
466
575
(-)a/t/db_dependent/api/v1/accountlines.t (+246 lines)
Line 0 Link Here
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 => 46;
21
use Test::Mojo;
22
use t::lib::TestBuilder;
23
24
use C4::Auth;
25
use C4::Context;
26
27
use Koha::Database;
28
29
my $builder = t::lib::TestBuilder->new();
30
31
my $dbh = C4::Context->dbh;
32
$dbh->{AutoCommit} = 0;
33
$dbh->{RaiseError} = 1;
34
35
$ENV{REMOTE_ADDR} = '127.0.0.1';
36
my $t = Test::Mojo->new('Koha::REST::V1');
37
38
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
39
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
40
41
$t->get_ok('/api/v1/accountlines')
42
  ->status_is(403);
43
44
$t->put_ok("/api/v1/accountlines/11224409" => json => {'amount' => -5})
45
    ->status_is(403);
46
47
$t->put_ok("/api/v1/accountlines/11224408/payment")
48
    ->status_is(403);
49
50
$t->put_ok("/api/v1/accountlines/11224407/partialpayment" => json => {'amount' => 8})
51
    ->status_is(403);
52
53
my $loggedinuser = $builder->build({
54
    source => 'Borrower',
55
    value => {
56
        branchcode   => $branchcode,
57
        categorycode => $categorycode,
58
        flags        => 1024
59
    }
60
});
61
62
my $borrower = $builder->build({
63
    source => 'Borrower',
64
    value => {
65
        branchcode   => $branchcode,
66
        categorycode => $categorycode,
67
    }
68
});
69
70
my $borrower2 = $builder->build({
71
    source => 'Borrower',
72
    value => {
73
        branchcode   => $branchcode,
74
        categorycode => $categorycode,
75
    }
76
});
77
my $borrowernumber = $borrower->{borrowernumber};
78
my $borrowernumber2 = $borrower2->{borrowernumber};
79
80
$dbh->do(q| DELETE FROM accountlines |);
81
$dbh->do(q|
82
    INSERT INTO accountlines (borrowernumber, amount, accounttype, amountoutstanding)
83
    VALUES (?, 20, 'A', 20), (?, 40, 'F', 40), (?, 80, 'F', 80), (?, 10, 'F', 10)
84
    |, undef, $borrowernumber, $borrowernumber, $borrowernumber, $borrowernumber2);
85
86
my $session = C4::Auth::get_session('');
87
$session->param('number', $loggedinuser->{ borrowernumber });
88
$session->param('id', $loggedinuser->{ userid });
89
$session->param('ip', '127.0.0.1');
90
$session->param('lasttime', time());
91
$session->flush;
92
93
my $tx = $t->ua->build_tx(GET => "/api/v1/accountlines?borrowernumber=$borrowernumber");
94
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
95
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
96
$t->request_ok($tx)
97
  ->status_is(200);
98
99
my $json = $t->tx->res->json;
100
ok(ref $json eq 'ARRAY', 'response is a JSON array');
101
ok(scalar @$json == 3, 'response array contains 3 elements');
102
103
$tx = $t->ua->build_tx(GET => "/api/v1/accountlines");
104
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
105
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
106
$t->request_ok($tx)
107
  ->status_is(200);
108
109
$json = $t->tx->res->json;
110
ok(ref $json eq 'ARRAY', 'response is a JSON array');
111
ok(scalar @$json == 4, 'response array contains 3 elements');
112
113
# Editing accountlines tests
114
my $put_data = {
115
    'amount' => -19,
116
    'amountoutstanding' => -19
117
};
118
119
120
$tx = $t->ua->build_tx(
121
    PUT => "/api/v1/accountlines/11224409"
122
        => json => $put_data);
123
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
124
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
125
$t->request_ok($tx)
126
    ->status_is(404);
127
128
my $accountline_to_edit = Koha::Accountlines->search({'borrowernumber' => $borrowernumber2})->unblessed()->[0];
129
130
$tx = $t->ua->build_tx(
131
    PUT => "/api/v1/accountlines/$accountline_to_edit->{accountlines_id}"
132
        => json => $put_data);
133
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
134
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
135
$t->request_ok($tx)
136
    ->status_is(200);
137
138
my $accountline_edited = Koha::Accountlines->search({'borrowernumber' => $borrowernumber2})->unblessed()->[0];
139
140
is($accountline_edited->{amount}, '-19.000000');
141
is($accountline_edited->{amountoutstanding}, '-19.000000');
142
143
144
# Payment tests
145
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/4562765765/payment");
146
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
147
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
148
$t->request_ok($tx)
149
  ->status_is(404);
150
151
my $accountline_to_pay = Koha::Accountlines->search({'borrowernumber' => $borrowernumber, 'amount' => 20})->unblessed()->[0];
152
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/$accountline_to_pay->{accountlines_id}/payment");
153
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
154
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
155
$t->request_ok($tx)
156
  ->status_is(200);
157
158
my $accountline_paid = Koha::Accountlines->search({'borrowernumber' => $borrowernumber, 'amount' => -20})->unblessed()->[0];
159
ok($accountline_paid);
160
161
# Partial payment tests
162
$put_data = {
163
    'amount' => 17,
164
    'note' => 'Partial payment'
165
};
166
167
$tx = $t->ua->build_tx(
168
    PUT => "/api/v1/accountlines/11224419/partialpayment"
169
        => json => $put_data);
170
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
171
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
172
$t->request_ok($tx)
173
    ->status_is(404);
174
175
my $accountline_to_partiallypay = Koha::Accountlines->search({'borrowernumber' => $borrowernumber, 'amount' => 80})->unblessed()->[0];
176
177
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/$accountline_to_partiallypay->{accountlines_id}/partialpayment" => json => {amount => 'foo'});
178
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
179
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
180
$t->request_ok($tx)
181
  ->status_is(400);
182
183
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/$accountline_to_partiallypay->{accountlines_id}/partialpayment" => json => $put_data);
184
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
185
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
186
$t->request_ok($tx)
187
  ->status_is(200);
188
189
$accountline_to_partiallypay = Koha::Accountlines->search({'borrowernumber' => $borrowernumber, 'amount' => 80})->unblessed()->[0];
190
is($accountline_to_partiallypay->{amountoutstanding}, '63.000000');
191
192
my $accountline_partiallypaid = Koha::Accountlines->search({'borrowernumber' => $borrowernumber, 'amount' => 17})->unblessed()->[0];
193
ok($accountline_partiallypaid);
194
195
# Pay amount tests
196
my $borrower3 = $builder->build({
197
    source => 'Borrower',
198
    value => {
199
        branchcode   => $branchcode,
200
        categorycode => $categorycode,
201
    }
202
});
203
my $borrowernumber3 = $borrower3->{borrowernumber};
204
205
$dbh->do(q|
206
    INSERT INTO accountlines (borrowernumber, amount, accounttype, amountoutstanding)
207
    VALUES (?, 26, 'A', 26)
208
    |, undef, $borrowernumber3);
209
210
$t->put_ok("/api/v1/accountlines/$borrowernumber3/amountpayment" => json => {'amount' => 8})
211
    ->status_is(403);
212
213
my $put_data2 = {
214
    'amount' => 24,
215
    'note' => 'Partial payment'
216
};
217
218
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/8789798797/amountpayment" => json => $put_data2);
219
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
220
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
221
$t->request_ok($tx)
222
  ->status_is(404);
223
224
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/$borrowernumber3/amountpayment" => json => {amount => 0});
225
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
226
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
227
$t->request_ok($tx)
228
  ->status_is(400);
229
230
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/$borrowernumber3/amountpayment" => json => {amount => 'foo'});
231
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
232
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
233
$t->request_ok($tx)
234
  ->status_is(400);
235
236
$tx = $t->ua->build_tx(PUT => "/api/v1/accountlines/$borrowernumber3/amountpayment" => json => $put_data2);
237
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
238
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
239
$t->request_ok($tx)
240
  ->status_is(200);
241
242
$accountline_partiallypaid = Koha::Accountlines->search({'borrowernumber' => $borrowernumber3, 'amount' => 26})->unblessed()->[0];
243
244
is($accountline_partiallypaid->{amountoutstanding}, '2.000000');
245
246
$dbh->rollback;
(-)a/t/db_dependent/api/v1/availability.t (+289 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# Copyright KohaSuomi 2016
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 => 165;
23
use Test::Mojo;
24
use t::lib::Mocks;
25
use t::lib::TestBuilder;
26
27
use Mojo::JSON;
28
29
use C4::Auth;
30
use C4::Circulation;
31
use C4::Context;
32
33
use Koha::Database;
34
use Koha::Items;
35
use Koha::Patron;
36
37
my $builder = t::lib::TestBuilder->new();
38
39
my $dbh = C4::Context->dbh;
40
$dbh->{AutoCommit} = 0;
41
$dbh->{RaiseError} = 1;
42
43
$ENV{REMOTE_ADDR} = '127.0.0.1';
44
my $t = Test::Mojo->new('Koha::REST::V1');
45
46
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
47
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
48
49
my $borrower = $builder->build({ source => 'Borrower' });
50
my $biblio = $builder->build({ source => 'Biblio' });
51
my $biblio2 = $builder->build({ source => 'Biblio' });
52
my $biblionumber = $biblio->{biblionumber};
53
my $biblionumber2 = $biblio2->{biblionumber};
54
55
my $module = new Test::MockModule('C4::Context');
56
$module->mock( 'userenv', sub { { branch => $borrower->{branchcode} } } );
57
58
# $item = available, $item2 = unavailable
59
my $items;
60
$items->{available} = build_item($biblionumber);
61
$items->{notforloan} = build_item($biblionumber2, { notforloan => 1 });
62
$items->{damaged} = build_item($biblionumber2, { damaged => 1 });
63
$items->{withdrawn} = build_item($biblionumber2, { withdrawn => 1 });
64
$items->{onloan}  = build_item($biblionumber2, { onloan => undef });
65
$items->{itemlost} = build_item($biblionumber2, { itemlost => 1 });
66
$items->{reserved} = build_item($biblionumber2);
67
my $reserve = Koha::Hold->new(
68
        {
69
            biblionumber   => $items->{reserved}->{biblionumber},
70
            itemnumber     => $items->{reserved}->{itemnumber},
71
            waitingdate    => '2000-01-01',
72
            borrowernumber => $borrower->{borrowernumber},
73
            branchcode     => $items->{reserved}->{homebranch},
74
            suspend        => 0,
75
        }
76
    )->store();
77
78
my $itemnumber = $items->{available}->{itemnumber};
79
80
$t->get_ok("/api/v1/availability/items?itemnumber=-500382")
81
  ->status_is(404);
82
83
$t->get_ok("/api/v1/availability/items?itemnumber=-500382+-500383")
84
  ->status_is(404);
85
86
$t->get_ok("/api/v1/availability/items?biblionumber=-500382")
87
  ->status_is(404);
88
89
$t->get_ok("/api/v1/availability/items?biblionumber=-500382+-500383")
90
  ->status_is(404);
91
92
t::lib::Mocks::mock_preference('OnSiteCheckouts', 0);
93
t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 0);
94
# available item
95
$t->get_ok("/api/v1/availability/items?itemnumber=$itemnumber")
96
  ->status_is(200)
97
  ->json_is('/0/itemnumber', $itemnumber)
98
  ->json_is('/0/biblionumber', $biblionumber)
99
  ->json_is('/0/checkout/available', Mojo::JSON->true)
100
  ->json_is('/0/checkout/description', [])
101
  ->json_is('/0/hold/available', Mojo::JSON->true)
102
  ->json_is('/0/hold/description', [])
103
  ->json_is('/0/local_use/available', Mojo::JSON->true)
104
  ->json_is('/0/local_use/description', [])
105
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
106
  ->json_is('/0/onsite_checkout/description', ["onsite_checkouts_disabled"])
107
  ->json_is('/0/hold_queue_length', 0);
108
t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
109
$t->get_ok("/api/v1/availability/items?biblionumber=$biblionumber")
110
  ->status_is(200)
111
  ->json_is('/0/itemnumber', $itemnumber)
112
  ->json_is('/0/biblionumber', $biblionumber)
113
  ->json_is('/0/checkout/available', Mojo::JSON->true)
114
  ->json_is('/0/checkout/description', [])
115
  ->json_is('/0/hold/available', Mojo::JSON->true)
116
  ->json_is('/0/hold/description', [])
117
  ->json_is('/0/local_use/available', Mojo::JSON->true)
118
  ->json_is('/0/local_use/description', [])
119
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
120
  ->json_is('/0/onsite_checkout/description', [])
121
  ->json_is('/0/hold_queue_length', 0);
122
123
# notforloan item
124
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{notforloan}->{itemnumber})
125
  ->status_is(200)
126
  ->json_is('/0/itemnumber', $items->{notforloan}->{itemnumber})
127
  ->json_is('/0/biblionumber', $biblionumber2)
128
  ->json_is('/0/checkout/available', Mojo::JSON->false)
129
  ->json_is('/0/checkout/description/0', "notforloan")
130
  ->json_is('/0/hold/available', Mojo::JSON->false)
131
  ->json_is('/0/hold/description', ["notforloan"])
132
  ->json_is('/0/local_use/available', Mojo::JSON->true)
133
  ->json_is('/0/local_use/description', [])
134
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
135
  ->json_is('/0/onsite_checkout/description', [])
136
  ->json_is('/0/hold_queue_length', 0);
137
t::lib::Mocks::mock_preference('OnSiteCheckouts', 0);
138
$t->get_ok("/api/v1/availability/items?itemnumber=$items->{notforloan}->{itemnumber}")
139
  ->status_is(200)
140
  ->json_is('/0/itemnumber', $items->{notforloan}->{itemnumber})
141
  ->json_is('/0/biblionumber', $biblionumber2)
142
  ->json_is('/0/checkout/available', Mojo::JSON->false)
143
  ->json_is('/0/checkout/description', ["notforloan"])
144
  ->json_is('/0/hold/available', Mojo::JSON->false)
145
  ->json_is('/0/hold/description', ["notforloan"])
146
  ->json_is('/0/local_use/available', Mojo::JSON->true)
147
  ->json_is('/0/local_use/description', [])
148
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
149
  ->json_is('/0/onsite_checkout/description', ["onsite_checkouts_disabled"])
150
  ->json_is('/0/hold_queue_length', 0);
151
t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
152
153
# damaged item
154
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{damaged}->{itemnumber})
155
  ->status_is(200)
156
  ->json_is('/0/itemnumber', $items->{damaged}->{itemnumber})
157
  ->json_is('/0/biblionumber', $biblionumber2)
158
  ->json_is('/0/checkout/available', Mojo::JSON->false)
159
  ->json_is('/0/checkout/description', ["damaged"])
160
  ->json_is('/0/hold/available', Mojo::JSON->false)
161
  ->json_is('/0/hold/description', ["damaged"])
162
  ->json_is('/0/local_use/available', Mojo::JSON->false)
163
  ->json_is('/0/local_use/description', ["damaged"])
164
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
165
  ->json_is('/0/onsite_checkout/description', ["damaged"])
166
  ->json_is('/0/hold_queue_length', 0);
167
t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1);
168
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{damaged}->{itemnumber})
169
  ->status_is(200)
170
  ->json_is('/0/itemnumber', $items->{damaged}->{itemnumber})
171
  ->json_is('/0/biblionumber', $biblionumber2)
172
  ->json_is('/0/checkout/available', Mojo::JSON->true)
173
  ->json_is('/0/checkout/description', ["damaged"])
174
  ->json_is('/0/hold/available', Mojo::JSON->true)
175
  ->json_is('/0/hold/description', ["damaged"])
176
  ->json_is('/0/local_use/available', Mojo::JSON->true)
177
  ->json_is('/0/local_use/description', ["damaged"])
178
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
179
  ->json_is('/0/onsite_checkout/description', ["damaged"])
180
  ->json_is('/0/hold_queue_length', 0);
181
182
# withdrawn item
183
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{withdrawn}->{itemnumber})
184
  ->status_is(200)
185
  ->json_is('/0/itemnumber', $items->{withdrawn}->{itemnumber})
186
  ->json_is('/0/biblionumber', $biblionumber2)
187
  ->json_is('/0/checkout/available', Mojo::JSON->false)
188
  ->json_is('/0/checkout/description', ["withdrawn"])
189
  ->json_is('/0/hold/available', Mojo::JSON->false)
190
  ->json_is('/0/hold/description', ["withdrawn"])
191
  ->json_is('/0/local_use/available', Mojo::JSON->false)
192
  ->json_is('/0/local_use/description', ["withdrawn"])
193
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
194
  ->json_is('/0/onsite_checkout/description', ["withdrawn"])
195
  ->json_is('/0/hold_queue_length', 0);
196
197
# lost item
198
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{itemlost}->{itemnumber})
199
  ->status_is(200)
200
  ->json_is('/0/itemnumber', $items->{itemlost}->{itemnumber})
201
  ->json_is('/0/biblionumber', $biblionumber2)
202
  ->json_is('/0/checkout/available', Mojo::JSON->false)
203
  ->json_is('/0/checkout/description', ["itemlost"])
204
  ->json_is('/0/hold/available', Mojo::JSON->false)
205
  ->json_is('/0/hold/description', ["itemlost"])
206
  ->json_is('/0/local_use/available', Mojo::JSON->false)
207
  ->json_is('/0/local_use/description', ["itemlost"])
208
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
209
  ->json_is('/0/onsite_checkout/description', ["itemlost"])
210
  ->json_is('/0/hold_queue_length', 0);
211
212
my $issue = AddIssue($borrower, $items->{onloan}->{barcode}, undef, 1);
213
214
# issued item
215
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{onloan}->{itemnumber})
216
  ->status_is(200)
217
  ->json_is('/0/itemnumber', $items->{onloan}->{itemnumber})
218
  ->json_is('/0/biblionumber', $biblionumber2)
219
  ->json_is('/0/checkout/available', Mojo::JSON->false)
220
  ->json_is('/0/checkout/description', ["onloan"])
221
  ->json_is('/0/hold/available', Mojo::JSON->true)
222
  ->json_is('/0/hold/description', [])
223
  ->json_is('/0/local_use/available', Mojo::JSON->false)
224
  ->json_is('/0/local_use/description', ["onloan"])
225
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
226
  ->json_is('/0/onsite_checkout/description', ["onloan"])
227
  ->json_is('/0/checkout/expected_available', $issue->date_due)
228
  ->json_is('/0/local_use/expected_available', $issue->date_due)
229
  ->json_is('/0/onsite_checkout/expected_available', $issue->date_due)
230
  ->json_is('/0/hold_queue_length', 0);
231
232
# reserved item
233
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{reserved}->{itemnumber})
234
  ->status_is(200)
235
  ->json_is('/0/itemnumber', $items->{reserved}->{itemnumber})
236
  ->json_is('/0/biblionumber', $biblionumber2)
237
  ->json_is('/0/checkout/available', Mojo::JSON->false)
238
  ->json_is('/0/checkout/description', ["reserved"])
239
  ->json_is('/0/hold/available', Mojo::JSON->true)
240
  ->json_is('/0/hold/description', [])
241
  ->json_is('/0/local_use/available', Mojo::JSON->false)
242
  ->json_is('/0/local_use/description', ["reserved"])
243
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
244
  ->json_is('/0/onsite_checkout/description', ["reserved"])
245
  ->json_is('/0/hold_queue_length', 1);
246
247
# multiple in one request
248
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{notforloan}->{itemnumber}."+$itemnumber+-500382")
249
  ->status_is(200)
250
  ->json_is('/0/itemnumber', $items->{notforloan}->{itemnumber})
251
  ->json_is('/0/biblionumber', $biblionumber2)
252
  ->json_is('/0/checkout/available', Mojo::JSON->false)
253
  ->json_is('/0/checkout/description/0', "notforloan")
254
  ->json_is('/0/hold/available', Mojo::JSON->false)
255
  ->json_is('/0/hold/description', ["notforloan"])
256
  ->json_is('/0/local_use/available', Mojo::JSON->true)
257
  ->json_is('/0/local_use/description', [])
258
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
259
  ->json_is('/0/onsite_checkout/description', [])
260
  ->json_is('/0/hold_queue_length', 0)
261
  ->json_is('/1/itemnumber', $itemnumber)
262
  ->json_is('/1/biblionumber', $biblionumber)
263
  ->json_is('/1/checkout/available', Mojo::JSON->true)
264
  ->json_is('/1/checkout/description', [])
265
  ->json_is('/1/hold/available', Mojo::JSON->true)
266
  ->json_is('/1/hold/description', [])
267
  ->json_is('/1/local_use/available', Mojo::JSON->true)
268
  ->json_is('/1/local_use/description', [])
269
  ->json_is('/1/onsite_checkout/available', Mojo::JSON->true)
270
  ->json_is('/1/onsite_checkout/description', [])
271
  ->json_is('/1/hold_queue_length', 0);
272
273
sub build_item {
274
    my ($biblionumber, $field) = @_;
275
276
    return $builder->build({
277
        source => 'Item',
278
        value => {
279
            biblionumber => $biblionumber,
280
            notforloan => $field->{notforloan} || 0,
281
            damaged => $field->{damaged} || 0,
282
            withdrawn => $field->{withdrawn} || 0,
283
            itemlost => $field->{itemlost} || 0,
284
            restricted => $field->{restricted} || undef,
285
            onloan => $field->{onloan} || undef,
286
            itype => $field->{itype} || undef,
287
        }
288
    });
289
}
(-)a/t/db_dependent/api/v1/biblios.t (+116 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# Copyright 2016 Koha-Suomi
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 => 7;
23
use Test::Mojo;
24
use t::lib::TestBuilder;
25
26
use C4::Auth;
27
use C4::Biblio;
28
use C4::Context;
29
use C4::Items;
30
31
use Koha::Database;
32
use Koha::Patron;
33
use Koha::Items;
34
35
my $builder = t::lib::TestBuilder->new();
36
37
my $dbh = C4::Context->dbh;
38
$dbh->{AutoCommit} = 0;
39
$dbh->{RaiseError} = 1;
40
41
$ENV{REMOTE_ADDR} = '127.0.0.1';
42
my $t = Test::Mojo->new('Koha::REST::V1');
43
44
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
45
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
46
my $borrower = $builder->build({
47
    source => 'Borrower',
48
    value => {
49
        branchcode   => $branchcode,
50
        categorycode => $categorycode,
51
        flags => 16,
52
    }
53
});
54
55
my $librarian = $builder->build({
56
    source => "Borrower",
57
    value => {
58
        categorycode => $categorycode,
59
        branchcode => $branchcode,
60
        flags => 4,
61
    },
62
});
63
64
my ($session) = create_session($borrower);
65
66
my $biblio = $builder->build({
67
    source => 'Biblio'
68
});
69
my $biblionumber = $biblio->{biblionumber};
70
my $item1 = $builder->build({
71
    source => 'Item',
72
    value => {
73
        biblionumber => $biblionumber,
74
    }
75
});
76
my $item2 = $builder->build({
77
    source => 'Item',
78
    value => {
79
        biblionumber => $biblionumber,
80
    }
81
});
82
my $item1number = $item1->{itemnumber};
83
my $item2number = $item2->{itemnumber};
84
85
my $nonExistentBiblionumber = -14362719;
86
my $tx = $t->ua->build_tx(GET => "/api/v1/biblios/$nonExistentBiblionumber");
87
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
88
$t->request_ok($tx)
89
  ->status_is(404);
90
91
$tx = $t->ua->build_tx(GET => "/api/v1/biblios/$biblionumber");
92
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
93
$t->request_ok($tx)
94
  ->status_is(200)
95
  ->json_is('/items/0/itemnumber' => $item1number)
96
  ->json_is('/items/1/itemnumber' => $item2number)
97
  ->json_is('/biblionumber' => $biblionumber);
98
99
$dbh->rollback;
100
101
sub create_session {
102
    my (@borrowers) = @_;
103
104
    my @sessions;
105
    foreach $borrower (@borrowers) {
106
        my $session = C4::Auth::get_session('');
107
        $session->param('number', $borrower->{borrowernumber});
108
        $session->param('id', $borrower->{userid});
109
        $session->param('ip', '127.0.0.1');
110
        $session->param('lasttime', time());
111
        $session->flush;
112
        push @sessions, $session;
113
    }
114
115
    return @sessions;
116
}
(-)a/t/db_dependent/api/v1/checkouts.t (+222 lines)
Line 0 Link Here
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 => 57;
21
use Test::MockModule;
22
use Test::Mojo;
23
use t::lib::Mocks;
24
use t::lib::TestBuilder;
25
26
use DateTime;
27
use MARC::Record;
28
29
use C4::Context;
30
use C4::Biblio;
31
use C4::Circulation;
32
use C4::Items;
33
34
use Koha::Database;
35
use Koha::Patron;
36
37
my $schema = Koha::Database->schema;
38
$schema->storage->txn_begin;
39
my $dbh = C4::Context->dbh;
40
my $builder = t::lib::TestBuilder->new;
41
$dbh->{RaiseError} = 1;
42
43
$ENV{REMOTE_ADDR} = '127.0.0.1';
44
my $t = Test::Mojo->new('Koha::REST::V1');
45
46
$dbh->do('DELETE FROM issues');
47
$dbh->do('DELETE FROM items');
48
$dbh->do('DELETE FROM issuingrules');
49
my $loggedinuser = $builder->build({ source => 'Borrower' });
50
51
$dbh->do(q{
52
    INSERT INTO user_permissions (borrowernumber, module_bit, code)
53
    VALUES (?, 1, 'circulate_remaining_permissions')
54
}, undef, $loggedinuser->{borrowernumber});
55
56
my $session = C4::Auth::get_session('');
57
$session->param('number', $loggedinuser->{ borrowernumber });
58
$session->param('id', $loggedinuser->{ userid });
59
$session->param('ip', '127.0.0.1');
60
$session->param('lasttime', time());
61
$session->flush;
62
63
my $borrower = $builder->build({ source => 'Borrower', value => { flags => 0 } });
64
my $borrowernumber = $borrower->{borrowernumber};
65
my $borrower_session = C4::Auth::get_session('');
66
$borrower_session->param('number', $borrowernumber);
67
$borrower_session->param('id', $borrower->{ userid });
68
$borrower_session->param('ip', '127.0.0.1');
69
$borrower_session->param('lasttime', time());
70
$borrower_session->flush;
71
72
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
73
my $module = new Test::MockModule('C4::Context');
74
$module->mock('userenv', sub { { branch => $branchcode } });
75
76
my $tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$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 $notexisting_borrowernumber = $borrowernumber + 1;
83
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$notexisting_borrowernumber");
84
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
85
$t->request_ok($tx)
86
  ->status_is(200)
87
  ->json_is([]);
88
89
my $biblionumber = create_biblio('RESTful Web APIs');
90
my $itemnumber1 = create_item($biblionumber, 'TEST000001');
91
my $itemnumber2 = create_item($biblionumber, 'TEST000002');
92
my $itemnumber3 = create_item($biblionumber, 'TEST000003');
93
94
my $date_due = DateTime->now->add(weeks => 2);
95
my $issue1 = C4::Circulation::AddIssue($borrower, 'TEST000001', $date_due);
96
my $date_due1 = Koha::DateUtils::dt_from_string( $issue1->date_due );
97
my $issue2 = C4::Circulation::AddIssue($borrower, 'TEST000002', $date_due);
98
my $date_due2 = Koha::DateUtils::dt_from_string( $issue2->date_due );
99
my $issue3 = C4::Circulation::AddIssue($loggedinuser, 'TEST000003', $date_due);
100
my $date_due3 = Koha::DateUtils::dt_from_string( $issue3->date_due );
101
102
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$borrowernumber");
103
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
104
$t->request_ok($tx)
105
  ->status_is(200)
106
  ->json_is('/0/borrowernumber' => $borrowernumber)
107
  ->json_is('/0/itemnumber' => $itemnumber1)
108
  ->json_is('/0/date_due' => $date_due1->ymd . ' ' . $date_due1->hms)
109
  ->json_is('/1/borrowernumber' => $borrowernumber)
110
  ->json_is('/1/itemnumber' => $itemnumber2)
111
  ->json_is('/1/date_due' => $date_due2->ymd . ' ' . $date_due2->hms)
112
  ->json_hasnt('/2');
113
114
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/".$issue3->issue_id);
115
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
116
$t->request_ok($tx)
117
  ->status_is(403)
118
  ->json_is({ error => "You don't have the required permission" });
119
120
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=".$loggedinuser->{borrowernumber});
121
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
122
$t->request_ok($tx)
123
  ->status_is(403)
124
  ->json_is({ error => "You don't have the required permission" });
125
126
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts?borrowernumber=$borrowernumber");
127
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
128
$t->request_ok($tx)
129
  ->status_is(200)
130
  ->json_is('/0/borrowernumber' => $borrowernumber)
131
  ->json_is('/0/itemnumber' => $itemnumber1)
132
  ->json_is('/0/date_due' => $date_due1->ymd . ' ' . $date_due1->hms)
133
  ->json_is('/1/borrowernumber' => $borrowernumber)
134
  ->json_is('/1/itemnumber' => $itemnumber2)
135
  ->json_is('/1/date_due' => $date_due2->ymd . ' ' . $date_due2->hms)
136
  ->json_hasnt('/2');
137
138
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue1->issue_id);
139
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
140
$t->request_ok($tx)
141
  ->status_is(200)
142
  ->json_is('/borrowernumber' => $borrowernumber)
143
  ->json_is('/itemnumber' => $itemnumber1)
144
  ->json_is('/date_due' => $date_due1->ymd . ' ' . $date_due1->hms)
145
  ->json_hasnt('/1');
146
147
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue1->issue_id);
148
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
149
$t->request_ok($tx)
150
  ->status_is(200)
151
  ->json_is('/date_due' => $date_due1->ymd . ' ' . $date_due1->hms);
152
153
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/" . $issue2->issue_id);
154
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
155
$t->request_ok($tx)
156
  ->status_is(200)
157
  ->json_is('/date_due' => $date_due2->ymd . ' ' . $date_due2->hms);
158
159
160
$dbh->do('DELETE FROM issuingrules');
161
$dbh->do(q{
162
    INSERT INTO issuingrules (categorycode, branchcode, itemtype, renewalperiod, renewalsallowed)
163
    VALUES (?, ?, ?, ?, ?)
164
}, {}, '*', '*', '*', 7, 1);
165
166
my $expected_datedue = DateTime->now->add(days => 14)->set(hour => 23, minute => 59, second => 0);
167
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue1->issue_id);
168
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
169
$t->request_ok($tx)
170
  ->status_is(200)
171
  ->json_is('/date_due' => $expected_datedue->ymd . ' ' . $expected_datedue->hms);
172
173
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue3->issue_id);
174
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
175
$t->request_ok($tx)
176
  ->status_is(403)
177
  ->json_is({ error => "You don't have the required permission" });
178
179
t::lib::Mocks::mock_preference( "OpacRenewalAllowed", 0 );
180
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue2->issue_id);
181
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
182
$t->request_ok($tx)
183
  ->status_is(403)
184
  ->json_is({ error => "You don't have the required permission" });
185
186
t::lib::Mocks::mock_preference( "OpacRenewalAllowed", 1 );
187
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue2->issue_id);
188
$tx->req->cookies({name => 'CGISESSID', value => $borrower_session->id});
189
$t->request_ok($tx)
190
  ->status_is(200)
191
  ->json_is('/date_due' => $expected_datedue->ymd . ' ' . $expected_datedue->hms);
192
193
$tx = $t->ua->build_tx(PUT => "/api/v1/checkouts/" . $issue1->issue_id);
194
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
195
$t->request_ok($tx)
196
  ->status_is(403)
197
  ->json_is({ error => 'Renewal not authorized (too_many)' });
198
199
sub create_biblio {
200
    my ($title) = @_;
201
202
    my $record = new MARC::Record;
203
    $record->append_fields(
204
        new MARC::Field('200', ' ', ' ', a => $title),
205
    );
206
207
    my ($biblionumber) = C4::Biblio::AddBiblio($record, '');
208
209
    return $biblionumber;
210
}
211
212
sub create_item {
213
    my ($biblionumber, $barcode) = @_;
214
215
    my $item = {
216
        barcode => $barcode,
217
    };
218
219
    my $itemnumber = C4::Items::AddItem($item, $biblionumber);
220
221
    return $itemnumber;
222
}
(-)a/t/db_dependent/api/v1/checkoutshistory.t (+160 lines)
Line 0 Link Here
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
use Koha::OldIssue;
36
use Koha::OldIssues;
37
38
my $schema = Koha::Database->schema;
39
$schema->storage->txn_begin;
40
my $dbh = C4::Context->dbh;
41
my $builder = t::lib::TestBuilder->new;
42
$dbh->{RaiseError} = 1;
43
44
$ENV{REMOTE_ADDR} = '127.0.0.1';
45
my $t = Test::Mojo->new('Koha::REST::V1');
46
47
$dbh->do('DELETE FROM issues');
48
$dbh->do('DELETE FROM items');
49
$dbh->do('DELETE FROM issuingrules');
50
my $loggedinuser = $builder->build({ source => 'Borrower' });
51
52
$dbh->do(q{
53
    INSERT INTO user_permissions (borrowernumber, module_bit, code)
54
    VALUES (?, 1, 'circulate_remaining_permissions')
55
}, undef, $loggedinuser->{borrowernumber});
56
57
my $session = C4::Auth::get_session('');
58
$session->param('number', $loggedinuser->{ borrowernumber });
59
$session->param('id', $loggedinuser->{ userid });
60
$session->param('ip', '127.0.0.1');
61
$session->param('lasttime', time());
62
$session->flush;
63
64
my $borrower = $builder->build({ source => 'Borrower' });
65
my $borrowernumber = $borrower->{borrowernumber};
66
67
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
68
my $module = new Test::MockModule('C4::Context');
69
$module->mock('userenv', sub { { branch => $branchcode } });
70
71
my $tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history?borrowernumber=$borrowernumber");
72
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
73
$t->request_ok($tx)
74
  ->status_is(200)
75
  ->json_is([]);
76
77
my $notexisting_borrowernumber = $borrowernumber + 1;
78
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history?borrowernumber=$notexisting_borrowernumber");
79
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
80
$t->request_ok($tx)
81
  ->status_is(404)
82
  ->json_has('/error');
83
84
my $biblionumber = create_biblio('RESTful Web APIs');
85
my $itemnumber1 = create_item($biblionumber, 'TEST000001');
86
my $itemnumber2 = create_item($biblionumber, 'TEST000002');
87
88
my $date_due = DateTime->now->add(weeks => 2);
89
90
my $issueId = Koha::OldIssues->count({}) + int rand(150000);
91
my $issue1;
92
$issue1 = Koha::OldIssue->new({ issue_id => $issueId, borrowernumber => $borrowernumber, itemnumber => $itemnumber1, date_due => $date_due});
93
$issue1->store();
94
95
my $date_due1 = Koha::DateUtils::dt_from_string( $issue1->date_due );
96
97
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history?borrowernumber=$borrowernumber");
98
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
99
$t->request_ok($tx)
100
  ->status_is(200)
101
  ->json_is('/0/issue_id' => $issueId)
102
  ->json_hasnt('/1')
103
  ->json_hasnt('/error');
104
105
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history/" . $issue1->issue_id);
106
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
107
$t->request_ok($tx)
108
  ->status_is(200)
109
  ->json_is('/borrowernumber' => $borrowernumber)
110
  ->json_is('/itemnumber' => $itemnumber1)
111
  ->json_is('/date_due' => $date_due1->ymd . ' ' . $date_due1->hms)
112
  ->json_hasnt('/error');
113
114
$issue1->delete();
115
116
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history/" . $issue1->issue_id);
117
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
118
$t->request_ok($tx)
119
  ->status_is(404)
120
  ->json_has('/error');
121
122
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history?borrowernumber=$borrowernumber");
123
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
124
$t->request_ok($tx)
125
  ->status_is(200)
126
  ->json_hasnt('/0')
127
  ->json_hasnt('/error');
128
129
Koha::Patrons->find($borrowernumber)->delete();
130
131
$tx = $t->ua->build_tx(GET => "/api/v1/checkouts/history?borrowernumber=$borrowernumber");
132
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
133
$t->request_ok($tx)
134
  ->status_is(404)
135
  ->json_has('/error');
136
137
sub create_biblio {
138
    my ($title) = @_;
139
140
    my $record = new MARC::Record;
141
    $record->append_fields(
142
        new MARC::Field('200', ' ', ' ', a => $title),
143
    );
144
145
    my ($biblionumber) = C4::Biblio::AddBiblio($record, '');
146
147
    return $biblionumber;
148
}
149
150
sub create_item {
151
    my ($biblionumber, $barcode) = @_;
152
153
    my $item = {
154
        barcode => $barcode,
155
    };
156
157
    my $itemnumber = C4::Items::AddItem($item, $biblionumber);
158
159
    return $itemnumber;
160
}
(-)a/t/db_dependent/api/v1/items.t (+117 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# Copyright 2016 Koha-Suomi
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 => 12;
23
use Test::Mojo;
24
use t::lib::TestBuilder;
25
26
use C4::Auth;
27
use C4::Biblio;
28
use C4::Context;
29
use C4::Items;
30
31
use Koha::Database;
32
use Koha::Patron;
33
use Koha::Items;
34
35
my $builder = t::lib::TestBuilder->new();
36
37
my $dbh = C4::Context->dbh;
38
$dbh->{AutoCommit} = 0;
39
$dbh->{RaiseError} = 1;
40
41
$ENV{REMOTE_ADDR} = '127.0.0.1';
42
my $t = Test::Mojo->new('Koha::REST::V1');
43
44
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
45
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
46
my $borrower = $builder->build({
47
    source => 'Borrower',
48
    value => {
49
        branchcode   => $branchcode,
50
        categorycode => $categorycode,
51
        flags => 16,
52
    }
53
});
54
55
my $librarian = $builder->build({
56
    source => "Borrower",
57
    value => {
58
        categorycode => $categorycode,
59
        branchcode => $branchcode,
60
        flags => 4,
61
    },
62
});
63
64
my ($session, $session2) = create_session($borrower, $librarian);
65
66
my $biblio = $builder->build({
67
    source => 'Biblio'
68
});
69
my $biblionumber = $biblio->{biblionumber};
70
my $item = $builder->build({
71
    source => 'Item',
72
    value => {
73
        biblionumber => $biblionumber,
74
    }
75
});
76
my $itemnumber = $item->{itemnumber};
77
78
my $nonExistentItemnumber = -14362719;
79
my $tx = $t->ua->build_tx(GET => "/api/v1/items/$nonExistentItemnumber");
80
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
81
$t->request_ok($tx)
82
  ->status_is(404);
83
84
$tx = $t->ua->build_tx(GET => "/api/v1/items/$itemnumber");
85
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
86
$t->request_ok($tx)
87
  ->status_is(200)
88
  ->json_is('/itemnumber' => $itemnumber)
89
  ->json_is('/biblionumber' => $biblionumber)
90
  ->json_is('/itemnotes_nonpublic' => undef);
91
92
$tx = $t->ua->build_tx(GET => "/api/v1/items/$itemnumber");
93
$tx->req->cookies({name => 'CGISESSID', value => $session2->id});
94
$t->request_ok($tx)
95
  ->status_is(200)
96
  ->json_is('/itemnumber' => $itemnumber)
97
  ->json_is('/biblionumber' => $biblionumber)
98
  ->json_is('/itemnotes_nonpublic' => $item->{itemnotes_nonpublic});
99
100
$dbh->rollback;
101
102
sub create_session {
103
    my (@borrowers) = @_;
104
105
    my @sessions;
106
    foreach $borrower (@borrowers) {
107
        my $session = C4::Auth::get_session('');
108
        $session->param('number', $borrower->{borrowernumber});
109
        $session->param('id', $borrower->{userid});
110
        $session->param('ip', '127.0.0.1');
111
        $session->param('lasttime', time());
112
        $session->flush;
113
        push @sessions, $session;
114
    }
115
116
    return @sessions;
117
}
(-)a/t/db_dependent/api/v1/libraries.t (+63 lines)
Line 0 Link Here
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 t::lib::TestBuilder;
21
22
use Test::More tests => 11;
23
use Test::Mojo;
24
25
use C4::Auth;
26
use C4::Context;
27
use Koha::Database;
28
29
BEGIN {
30
    use_ok('Koha::Object');
31
    use_ok('Koha::Libraries');
32
}
33
34
my $schema  = Koha::Database->schema;
35
my $dbh     = C4::Context->dbh;
36
my $builder = t::lib::TestBuilder->new;
37
38
$ENV{REMOTE_ADDR} = '127.0.0.1';
39
my $t = Test::Mojo->new('Koha::REST::V1');
40
41
$schema->storage->txn_begin;
42
43
my $branch = $builder->build({ source => 'Branch' });
44
45
my $tx = $t->ua->build_tx(GET => '/api/v1/libraries');
46
#$tx->req->cookies({name => 'CGISESSID', value => $session->id});
47
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
48
$t->request_ok($tx)
49
  ->status_is(200);
50
51
$tx = $t->ua->build_tx(GET => "/api/v1/libraries/" . $branch->{ branchcode });
52
#$tx->req->cookies({name => 'CGISESSID', value => $session->id});
53
$t->request_ok($tx)
54
  ->status_is(200)
55
  ->json_is('/branchcode' => $branch->{ branchcode })
56
  ->json_is('/branchname' => $branch->{ branchname });
57
58
$tx = $t->ua->build_tx(GET => "/api/v1/libraries/" . "nonexistent");
59
$t->request_ok($tx)
60
  ->status_is(404)
61
  ->json_is('/error' => "Library with branchcode \"nonexistent\" not found");
62
63
$schema->storage->txn_rollback;
(-)a/t/db_dependent/api/v1/patrons.t (-15 / +153 lines)
Lines 17-44 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 10;
21
use Test::Mojo;
22
use t::lib::TestBuilder;
20
use t::lib::TestBuilder;
23
21
22
use Test::More tests => 64;
23
use Test::Mojo;
24
24
use C4::Auth;
25
use C4::Auth;
25
use C4::Context;
26
use C4::Context;
26
27
use Koha::Database;
27
use Koha::Database;
28
use Koha::Patron;
29
28
30
my $builder = t::lib::TestBuilder->new();
29
BEGIN {
30
    use_ok('Koha::Object');
31
    use_ok('Koha::Patron');
32
}
31
33
32
my $dbh = C4::Context->dbh;
34
my $schema  = Koha::Database->schema;
33
$dbh->{AutoCommit} = 0;
35
my $dbh     = C4::Context->dbh;
34
$dbh->{RaiseError} = 1;
36
my $builder = t::lib::TestBuilder->new;
35
37
36
$ENV{REMOTE_ADDR} = '127.0.0.1';
38
$ENV{REMOTE_ADDR} = '127.0.0.1';
37
my $t = Test::Mojo->new('Koha::REST::V1');
39
my $t = Test::Mojo->new('Koha::REST::V1');
38
40
41
$schema->storage->txn_begin;
42
39
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
43
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
40
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
44
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
41
my $borrower = $builder->build({
45
my $patron = $builder->build({
42
    source => 'Borrower',
46
    source => 'Borrower',
43
    value => {
47
    value => {
44
        branchcode   => $branchcode,
48
        branchcode   => $branchcode,
Lines 46-55 my $borrower = $builder->build({ Link Here
46
    }
50
    }
47
});
51
});
48
52
53
### GET /api/v1/patrons
54
49
$t->get_ok('/api/v1/patrons')
55
$t->get_ok('/api/v1/patrons')
50
  ->status_is(403);
56
  ->status_is(403);
51
57
52
$t->get_ok("/api/v1/patrons/" . $borrower->{ borrowernumber })
58
$t->get_ok("/api/v1/patrons/" . $patron->{ borrowernumber })
53
  ->status_is(403);
59
  ->status_is(403);
54
60
55
my $loggedinuser = $builder->build({
61
my $loggedinuser = $builder->build({
Lines 73-84 $tx->req->cookies({name => 'CGISESSID', value => $session->id}); Link Here
73
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
79
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
74
$t->request_ok($tx)
80
$t->request_ok($tx)
75
  ->status_is(200);
81
  ->status_is(200);
82
ok(@{$tx->res->json} >= 1, 'Json response lists all when no params given');
83
84
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $patron->{ borrowernumber });
85
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
86
$t->request_ok($tx)
87
  ->status_is(200)
88
  ->json_is('/borrowernumber' => $patron->{ borrowernumber })
89
  ->json_is('/surname' => $patron->{ surname });
90
91
$tx = $t->ua->build_tx(GET => '/api/v1/patrons' => form => {surname => 'nonexistent'});
92
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
93
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
94
$t->request_ok($tx)
95
  ->status_is(200);
96
ok(@{$tx->res->json} == 0, "Json response yields no results when params doesn't match");
76
97
77
$tx = $t->ua->build_tx(GET => "/api/v1/patrons/" . $borrower->{ borrowernumber });
98
$tx = $t->ua->build_tx(GET => '/api/v1/patrons' => form => {surname => $patron->{ surname }});
78
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
99
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
100
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
79
$t->request_ok($tx)
101
$t->request_ok($tx)
80
  ->status_is(200)
102
  ->status_is(200)
81
  ->json_is('/borrowernumber' => $borrower->{ borrowernumber })
103
  ->json_has($patron);
82
  ->json_is('/surname' => $borrower->{ surname });
104
ok(@{$tx->res->json} == 1, 'Json response yields expected results when params match');
105
106
### POST /api/v1/patrons
107
108
my $newpatron = {
109
  branchcode   => $branchcode,
110
  categorycode => $categorycode,
111
  surname      => "TestUser",
112
  cardnumber => "123456",
113
  userid => "testuser"
114
};
115
116
$newpatron->{ branchcode } = "nonexistent"; # Test invalid branchcode
117
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
118
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
119
$t->request_ok($tx)
120
  ->status_is(404)
121
  ->json_is('/error' => "Library with branchcode \"nonexistent\" does not exist");
122
123
$newpatron->{ branchcode } = $branchcode;
124
$newpatron->{ categorycode } = "nonexistent"; # Test invalid patron category
125
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
126
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
127
$t->request_ok($tx)
128
  ->status_is(404)
129
  ->json_is('/error' => "Patron category \"nonexistent\" does not exist");
130
$newpatron->{ categorycode } = $categorycode;
131
132
$newpatron->{ falseproperty } = "Non existent property";
133
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
134
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
135
$t->request_ok($tx)
136
  ->status_is(500)
137
  ->json_is('/error' => "Something went wrong, check Koha logs for details");
138
139
delete $newpatron->{ falseproperty };
140
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
141
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
142
$t->request_ok($tx)
143
  ->status_is(201, 'Patron created successfully')
144
  ->json_has('/borrowernumber', 'got a borrowernumber')
145
  ->json_is('/cardnumber', $newpatron->{ cardnumber })
146
  ->json_is('/surname' => $newpatron->{ surname })
147
  ->json_is('/firstname' => $newpatron->{ firstname });
148
$newpatron->{borrowernumber} = $tx->res->json->{borrowernumber};
149
150
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
151
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
152
$t->request_ok($tx)
153
  ->status_is(409)
154
  ->json_has('/error', 'Fails when trying to POST duplicate cardnumber or userid')
155
  ->json_has('/conflict', { userid => $newpatron->{ userid }, cardnumber => $newpatron->{ cardnumber } });
156
157
### PUT /api/v1/patrons
158
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/0" => json => {});
159
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
160
$t->request_ok($tx)
161
  ->status_is(404)
162
  ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
163
164
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => {categorycode => "nonexistent"});
165
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
166
$t->request_ok($tx)
167
  ->status_is(404)
168
  ->json_is('/error' => "Patron category \"nonexistent\" does not exist");
169
170
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => {branchcode => "nonexistent"});
171
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
172
$t->request_ok($tx)
173
  ->status_is(404)
174
  ->json_is('/error' => "Library with branchcode \"nonexistent\" does not exist");
175
176
$newpatron->{ falseproperty } = "Non existent property";
177
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
178
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
179
$t->request_ok($tx)
180
  ->status_is(500)
181
  ->json_is('/error' => "Something went wrong, check Koha logs for details");
182
delete $newpatron->{ falseproperty };
183
184
$newpatron->{ cardnumber } = $patron-> { cardnumber };
185
$newpatron->{ userid } = $patron-> { userid };
186
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
187
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
188
$t->request_ok($tx)
189
  ->status_is(409)
190
  ->json_has('/error' => "Fails when trying to update to an existing cardnumber or userid")
191
  ->json_has('/conflict', { cardnumber => $patron->{ cardnumber }, userid => $patron->{ userid } });
192
193
$newpatron->{ cardnumber } = "123456";
194
$newpatron->{ userid } = "testuser";
195
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
196
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
197
$t->request_ok($tx)
198
  ->status_is(204, 'No changes - patron NOT updated');
199
200
$newpatron->{ cardnumber } = "234567";
201
$newpatron->{ userid } = "updatedtestuser";
202
$newpatron->{ surname } = "UpdatedTestUser";
203
204
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => $newpatron);
205
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
206
$t->request_ok($tx)
207
  ->status_is(200, 'Patron updated successfully')
208
  ->json_has($newpatron);
209
210
### DELETE /api/v1/patrons
211
212
$tx = $t->ua->build_tx(DELETE => "/api/v1/patrons/0");
213
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
214
$t->request_ok($tx)
215
  ->status_is(404, 'Patron not found');
216
217
$tx = $t->ua->build_tx(DELETE => "/api/v1/patrons/" . $newpatron->{ borrowernumber });
218
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
219
$t->request_ok($tx)
220
  ->status_is(200, 'Patron deleted successfully');
221
222
$schema->storage->txn_rollback;
83
223
84
$dbh->rollback;
85
- 

Return to bug 16652