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

(-)a/Koha/REST/V1/Availability.pm (+107 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
                            } });
37
38
        push @items, _item_availability($found_items);
39
    }
40
41
    return $c->$cb({ error => "Item(s) not found"}, 404) unless scalar @items;
42
    return $c->$cb([ @items ], 200);
43
}
44
45
sub _item_availability {
46
    my ($items) = @_;
47
48
    if (ref($items) eq 'Koha::Items') {
49
        $items = $items->as_list;
50
    }
51
52
    my @item_availabilities;
53
    foreach my $item (@$items) {
54
        unless (ref($item) eq 'Koha::Item') {
55
            $item = Koha::Items->find($item);
56
            next unless $item;
57
        }
58
59
        my $availabilities = _swaggerize_availabilities($item->availabilities);
60
61
        my $holds;
62
        $holds->{'hold_queue_length'} = $item->hold_queue_length;
63
64
        my $iteminfo = {
65
            itemnumber => $item->itemnumber,
66
            barcode => $item->barcode,
67
            biblionumber => $item->biblionumber,
68
            biblioitemnumber => $item->biblioitemnumber,
69
            enumchron => $item->enumchron,
70
            holdingbranch => $item->holdingbranch,
71
            homebranch => $item->homebranch,
72
            location => $item->location,
73
            itemcallnumber => $item->itemcallnumber,
74
            itemnotes => $item->itemnotes,
75
        };
76
77
        # merge availability, hold information and item information
78
        push @item_availabilities, { %{$availabilities}, %{$holds}, %{$iteminfo} };
79
    }
80
81
    return @item_availabilities;
82
}
83
84
sub _swaggerize_availabilities {
85
    my ($availabilities) = @_;
86
87
    $availabilities->use_stored_values(1);
88
    my $avail_hash = {
89
        hold => $availabilities->hold,
90
        checkout => $availabilities->issue,
91
        local_use => $availabilities->local_use,
92
        onsite_checkout => $availabilities->onsite_checkout,
93
    };
94
95
    foreach my $availability (keys $avail_hash) {
96
        delete $avail_hash->{$availability}->{availability_needs_confirmation};
97
        $avail_hash->{$availability}->available(
98
        $avail_hash->{$availability}->available
99
                             ? Mojo::JSON->true
100
                             : Mojo::JSON->false);
101
        $avail_hash->{$availability} = { %{$avail_hash->{$availability}} };
102
    }
103
104
    return $avail_hash;
105
}
106
107
1;
(-)a/api/v1/swagger/definitions.json (+6 lines)
Lines 1-4 Link Here
1
{
1
{
2
  "availability": {
3
    "$ref": "definitions/availability.json"
4
  },
5
  "availabilities": {
6
    "$ref": "definitions/availabilities.json"
7
  },
2
  "city": {
8
  "city": {
3
    "$ref": "definitions/city.json"
9
    "$ref": "definitions/city.json"
4
  },
10
  },
(-)a/api/v1/swagger/parameters.json (+6 lines)
Lines 1-4 Link Here
1
{
1
{
2
  "biblionumbersQueryParam": {
3
    "$ref": "parameters/biblio.json#/biblionumbersQueryParam"
4
  },
2
  "borrowernumberPathParam": {
5
  "borrowernumberPathParam": {
3
    "$ref": "parameters/patron.json#/borrowernumberPathParam"
6
    "$ref": "parameters/patron.json#/borrowernumberPathParam"
4
  },
7
  },
Lines 13-17 Link Here
13
  },
16
  },
14
  "itemnumberPathParam": {
17
  "itemnumberPathParam": {
15
    "$ref": "parameters/item.json#/itemnumberPathParam"
18
    "$ref": "parameters/item.json#/itemnumberPathParam"
19
  },
20
  "itemnumbersQueryParam": {
21
    "$ref": "parameters/item.json#/itemnumbersQueryParam"
16
  }
22
  }
17
}
23
}
(-)a/api/v1/swagger/parameters/item.json (+10 lines)
Lines 5-9 Link Here
5
    "description": "Internal item identifier",
5
    "description": "Internal item identifier",
6
    "required": true,
6
    "required": true,
7
    "type": "integer"
7
    "type": "integer"
8
  },
9
  "itemnumbersQueryParam": {
10
    "name": "itemnumber",
11
    "in": "query",
12
    "description": "Internal items identifier",
13
    "type": "array",
14
    "items": {
15
      "type": "integer"
16
    },
17
    "collectionFormat": "ssv"
8
  }
18
  }
9
}
19
}
(-)a/api/v1/swagger/paths.json (+3 lines)
Lines 1-4 Link Here
1
{
1
{
2
  "/availability/items": {
3
    "$ref": "paths/availability.json#/~1availability~1items"
4
  },
2
  "/cities": {
5
  "/cities": {
3
    "$ref": "paths/cities.json#/~1cities"
6
    "$ref": "paths/cities.json#/~1cities"
4
  },
7
  },
(-)a/t/db_dependent/api/v1/availability.t (-1 / +292 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# Copyright Koha-Suomi Oy 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 $priority= C4::Reserves::CalculatePriority($items->{reserved}->{biblionumber});
68
my $reserve_id = C4::Reserves::AddReserve(
69
    $items->{reserved}->{homebranch},
70
    $borrower->{borrowernumber},
71
    $items->{reserved}->{biblionumber},
72
    undef,
73
    $priority,
74
    undef, undef, undef,
75
    $$biblio{title},
76
    $items->{reserved}->{itemnumber},
77
    undef
78
);
79
my $reserve = Koha::Holds->find($reserve_id);
80
81
my $itemnumber = $items->{available}->{itemnumber};
82
83
$t->get_ok("/api/v1/availability/items?itemnumber=-500382")
84
  ->status_is(404);
85
86
$t->get_ok("/api/v1/availability/items?itemnumber=-500382+-500383")
87
  ->status_is(404);
88
89
$t->get_ok("/api/v1/availability/items?biblionumber=-500382")
90
  ->status_is(404);
91
92
$t->get_ok("/api/v1/availability/items?biblionumber=-500382+-500383")
93
  ->status_is(404);
94
95
t::lib::Mocks::mock_preference('OnSiteCheckouts', 0);
96
t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 0);
97
# available item
98
$t->get_ok("/api/v1/availability/items?itemnumber=$itemnumber")
99
  ->status_is(200)
100
  ->json_is('/0/itemnumber', $itemnumber)
101
  ->json_is('/0/biblionumber', $biblionumber)
102
  ->json_is('/0/checkout/available', Mojo::JSON->true)
103
  ->json_is('/0/checkout/description', [])
104
  ->json_is('/0/hold/available', Mojo::JSON->true)
105
  ->json_is('/0/hold/description', [])
106
  ->json_is('/0/local_use/available', Mojo::JSON->true)
107
  ->json_is('/0/local_use/description', [])
108
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
109
  ->json_is('/0/onsite_checkout/description', ["onsite_checkouts_disabled"])
110
  ->json_is('/0/hold_queue_length', 0);
111
t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
112
$t->get_ok("/api/v1/availability/items?biblionumber=$biblionumber")
113
  ->status_is(200)
114
  ->json_is('/0/itemnumber', $itemnumber)
115
  ->json_is('/0/biblionumber', $biblionumber)
116
  ->json_is('/0/checkout/available', Mojo::JSON->true)
117
  ->json_is('/0/checkout/description', [])
118
  ->json_is('/0/hold/available', Mojo::JSON->true)
119
  ->json_is('/0/hold/description', [])
120
  ->json_is('/0/local_use/available', Mojo::JSON->true)
121
  ->json_is('/0/local_use/description', [])
122
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
123
  ->json_is('/0/onsite_checkout/description', [])
124
  ->json_is('/0/hold_queue_length', 0);
125
126
# notforloan item
127
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{notforloan}->{itemnumber})
128
  ->status_is(200)
129
  ->json_is('/0/itemnumber', $items->{notforloan}->{itemnumber})
130
  ->json_is('/0/biblionumber', $biblionumber2)
131
  ->json_is('/0/checkout/available', Mojo::JSON->false)
132
  ->json_is('/0/checkout/description/0', "notforloan")
133
  ->json_is('/0/hold/available', Mojo::JSON->false)
134
  ->json_is('/0/hold/description', ["notforloan"])
135
  ->json_is('/0/local_use/available', Mojo::JSON->true)
136
  ->json_is('/0/local_use/description', [])
137
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
138
  ->json_is('/0/onsite_checkout/description', [])
139
  ->json_is('/0/hold_queue_length', 0);
140
t::lib::Mocks::mock_preference('OnSiteCheckouts', 0);
141
$t->get_ok("/api/v1/availability/items?itemnumber=$items->{notforloan}->{itemnumber}")
142
  ->status_is(200)
143
  ->json_is('/0/itemnumber', $items->{notforloan}->{itemnumber})
144
  ->json_is('/0/biblionumber', $biblionumber2)
145
  ->json_is('/0/checkout/available', Mojo::JSON->false)
146
  ->json_is('/0/checkout/description', ["notforloan"])
147
  ->json_is('/0/hold/available', Mojo::JSON->false)
148
  ->json_is('/0/hold/description', ["notforloan"])
149
  ->json_is('/0/local_use/available', Mojo::JSON->true)
150
  ->json_is('/0/local_use/description', [])
151
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
152
  ->json_is('/0/onsite_checkout/description', ["onsite_checkouts_disabled"])
153
  ->json_is('/0/hold_queue_length', 0);
154
t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
155
156
# damaged item
157
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{damaged}->{itemnumber})
158
  ->status_is(200)
159
  ->json_is('/0/itemnumber', $items->{damaged}->{itemnumber})
160
  ->json_is('/0/biblionumber', $biblionumber2)
161
  ->json_is('/0/checkout/available', Mojo::JSON->false)
162
  ->json_is('/0/checkout/description', ["damaged"])
163
  ->json_is('/0/hold/available', Mojo::JSON->false)
164
  ->json_is('/0/hold/description', ["damaged"])
165
  ->json_is('/0/local_use/available', Mojo::JSON->false)
166
  ->json_is('/0/local_use/description', ["damaged"])
167
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
168
  ->json_is('/0/onsite_checkout/description', ["damaged"])
169
  ->json_is('/0/hold_queue_length', 0);
170
t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1);
171
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{damaged}->{itemnumber})
172
  ->status_is(200)
173
  ->json_is('/0/itemnumber', $items->{damaged}->{itemnumber})
174
  ->json_is('/0/biblionumber', $biblionumber2)
175
  ->json_is('/0/checkout/available', Mojo::JSON->true)
176
  ->json_is('/0/checkout/description', ["damaged"])
177
  ->json_is('/0/hold/available', Mojo::JSON->true)
178
  ->json_is('/0/hold/description', ["damaged"])
179
  ->json_is('/0/local_use/available', Mojo::JSON->true)
180
  ->json_is('/0/local_use/description', ["damaged"])
181
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
182
  ->json_is('/0/onsite_checkout/description', ["damaged"])
183
  ->json_is('/0/hold_queue_length', 0);
184
185
# withdrawn item
186
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{withdrawn}->{itemnumber})
187
  ->status_is(200)
188
  ->json_is('/0/itemnumber', $items->{withdrawn}->{itemnumber})
189
  ->json_is('/0/biblionumber', $biblionumber2)
190
  ->json_is('/0/checkout/available', Mojo::JSON->false)
191
  ->json_is('/0/checkout/description', ["withdrawn"])
192
  ->json_is('/0/hold/available', Mojo::JSON->false)
193
  ->json_is('/0/hold/description', ["withdrawn"])
194
  ->json_is('/0/local_use/available', Mojo::JSON->false)
195
  ->json_is('/0/local_use/description', ["withdrawn"])
196
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
197
  ->json_is('/0/onsite_checkout/description', ["withdrawn"])
198
  ->json_is('/0/hold_queue_length', 0);
199
200
# lost item
201
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{itemlost}->{itemnumber})
202
  ->status_is(200)
203
  ->json_is('/0/itemnumber', $items->{itemlost}->{itemnumber})
204
  ->json_is('/0/biblionumber', $biblionumber2)
205
  ->json_is('/0/checkout/available', Mojo::JSON->false)
206
  ->json_is('/0/checkout/description', ["itemlost"])
207
  ->json_is('/0/hold/available', Mojo::JSON->false)
208
  ->json_is('/0/hold/description', ["itemlost"])
209
  ->json_is('/0/local_use/available', Mojo::JSON->false)
210
  ->json_is('/0/local_use/description', ["itemlost"])
211
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
212
  ->json_is('/0/onsite_checkout/description', ["itemlost"])
213
  ->json_is('/0/hold_queue_length', 0);
214
215
my $issue = AddIssue($borrower, $items->{onloan}->{barcode}, undef, 1);
216
217
# issued item
218
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{onloan}->{itemnumber})
219
  ->status_is(200)
220
  ->json_is('/0/itemnumber', $items->{onloan}->{itemnumber})
221
  ->json_is('/0/biblionumber', $biblionumber2)
222
  ->json_is('/0/checkout/available', Mojo::JSON->false)
223
  ->json_is('/0/checkout/description', ["onloan"])
224
  ->json_is('/0/hold/available', Mojo::JSON->true)
225
  ->json_is('/0/hold/description', [])
226
  ->json_is('/0/local_use/available', Mojo::JSON->false)
227
  ->json_is('/0/local_use/description', ["onloan"])
228
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
229
  ->json_is('/0/onsite_checkout/description', ["onloan"])
230
  ->json_is('/0/checkout/expected_available', $issue->date_due)
231
  ->json_is('/0/local_use/expected_available', $issue->date_due)
232
  ->json_is('/0/onsite_checkout/expected_available', $issue->date_due)
233
  ->json_is('/0/hold_queue_length', 0);
234
235
# reserved item
236
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{reserved}->{itemnumber})
237
  ->status_is(200)
238
  ->json_is('/0/itemnumber', $items->{reserved}->{itemnumber})
239
  ->json_is('/0/biblionumber', $biblionumber2)
240
  ->json_is('/0/checkout/available', Mojo::JSON->false)
241
  ->json_is('/0/checkout/description', ["reserved"])
242
  ->json_is('/0/hold/available', Mojo::JSON->true)
243
  ->json_is('/0/hold/description', [])
244
  ->json_is('/0/local_use/available', Mojo::JSON->false)
245
  ->json_is('/0/local_use/description', ["reserved"])
246
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->false)
247
  ->json_is('/0/onsite_checkout/description', ["reserved"])
248
  ->json_is('/0/hold_queue_length', 1);
249
250
# multiple in one request
251
$t->get_ok("/api/v1/availability/items?itemnumber=".$items->{notforloan}->{itemnumber}."+$itemnumber+-500382")
252
  ->status_is(200)
253
  ->json_is('/0/itemnumber', $items->{notforloan}->{itemnumber})
254
  ->json_is('/0/biblionumber', $biblionumber2)
255
  ->json_is('/0/checkout/available', Mojo::JSON->false)
256
  ->json_is('/0/checkout/description/0', "notforloan")
257
  ->json_is('/0/hold/available', Mojo::JSON->false)
258
  ->json_is('/0/hold/description', ["notforloan"])
259
  ->json_is('/0/local_use/available', Mojo::JSON->true)
260
  ->json_is('/0/local_use/description', [])
261
  ->json_is('/0/onsite_checkout/available', Mojo::JSON->true)
262
  ->json_is('/0/onsite_checkout/description', [])
263
  ->json_is('/0/hold_queue_length', 0)
264
  ->json_is('/1/itemnumber', $itemnumber)
265
  ->json_is('/1/biblionumber', $biblionumber)
266
  ->json_is('/1/checkout/available', Mojo::JSON->true)
267
  ->json_is('/1/checkout/description', [])
268
  ->json_is('/1/hold/available', Mojo::JSON->true)
269
  ->json_is('/1/hold/description', [])
270
  ->json_is('/1/local_use/available', Mojo::JSON->true)
271
  ->json_is('/1/local_use/description', [])
272
  ->json_is('/1/onsite_checkout/available', Mojo::JSON->true)
273
  ->json_is('/1/onsite_checkout/description', [])
274
  ->json_is('/1/hold_queue_length', 0);
275
276
sub build_item {
277
    my ($biblionumber, $field) = @_;
278
279
    return $builder->build({
280
        source => 'Item',
281
        value => {
282
            biblionumber => $biblionumber,
283
            notforloan => $field->{notforloan} || 0,
284
            damaged => $field->{damaged} || 0,
285
            withdrawn => $field->{withdrawn} || 0,
286
            itemlost => $field->{itemlost} || 0,
287
            restricted => $field->{restricted} || undef,
288
            onloan => $field->{onloan} || undef,
289
            itype => $field->{itype} || undef,
290
        }
291
    });
292
}

Return to bug 16826