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

(-)a/Koha/Item.pm (+31 lines)
Lines 25-30 use Koha::Database; Link Here
25
25
26
use C4::Context;
26
use C4::Context;
27
use C4::Circulation qw(GetIssuingRule);
27
use C4::Circulation qw(GetIssuingRule);
28
use Koha::Item::Availabilities;
28
use Koha::Item::Transfer;
29
use Koha::Item::Transfer;
29
use Koha::Patrons;
30
use Koha::Patrons;
30
use Koha::Libraries;
31
use Koha::Libraries;
Lines 41-46 Koha::Item - Koha Item object class Link Here
41
42
42
=cut
43
=cut
43
44
45
=head3 availabilities
46
47
my $availabilities = $item->availabilities;
48
49
# Available for checkout?
50
$availabilities->issue->available
51
52
Returns Koha::Item::Availabilities object which holds different types of
53
availabilities for this item.
54
55
=cut
56
57
sub availabilities {
58
    my ($self) = @_;
59
60
    return Koha::Item::Availabilities->new($self);
61
}
62
44
=head3 effective_itemtype
63
=head3 effective_itemtype
45
64
46
Returns the itemtype for the item based on whether item level itemtypes are set or not.
65
Returns the itemtype for the item based on whether item level itemtypes are set or not.
Lines 53-58 sub effective_itemtype { Link Here
53
    return $self->_result()->effective_itemtype();
72
    return $self->_result()->effective_itemtype();
54
}
73
}
55
74
75
=head3 hold_queue_length
76
77
=cut
78
79
sub hold_queue_length {
80
    my ( $self ) = @_;
81
82
    my $reserves = Koha::Holds->search({ itemnumber => $self->itemnumber });
83
    return $reserves->count() if $reserves;
84
    return 0;
85
}
86
56
=head3 home_branch
87
=head3 home_branch
57
88
58
=cut
89
=cut
(-)a/Koha/Item/Availabilities.pm (+253 lines)
Line 0 Link Here
1
package Koha::Item::Availabilities;
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 C4::Context;
23
use C4::Reserves;
24
25
use Koha::Exceptions;
26
use Koha::Issues;
27
use Koha::Item::Availability;
28
use Koha::Items;
29
use Koha::ItemTypes;
30
31
=head1 NAME
32
33
Koha::Item::Availabilities - Koha Item Availabilities object class
34
35
=head1 SYNOPSIS
36
37
  my $availabilities = Koha::Items->find(1337)->availabilities;
38
39
  print "Available for checkout!" if $availabilities->checkout->available;
40
41
=head1 DESCRIPTION
42
43
This class holds logic for calculating different types of availabilities.
44
45
=head2 Class Methods
46
47
=cut
48
49
=head3 new
50
51
=cut
52
53
sub new {
54
    my ($class, $params) = @_;
55
56
    my $self = {};
57
    my $item;
58
59
    unless(ref($params) eq 'Koha::Item') {
60
        Koha::Exceptions::MissingParameter->throw({
61
            error => "Missing parameter itemnumber",
62
            parameter => "itemnumber",
63
        }) unless $params->{'itemnumber'};
64
65
        $item = Koha::Items->find($params->{'itemnumber'});
66
    } else {
67
        $item = $params;
68
    }
69
70
    $self->{'item'} = $item;
71
    $self->{'_use_stored_values'} = 0;
72
73
    bless($self, $class);
74
}
75
76
=head3 hold
77
78
Availability for holds. Does not consider patron status.
79
80
=cut
81
82
sub hold {
83
    my ($self) = @_;
84
85
    my $item = $self->item;
86
    my $availability = Koha::Item::Availability->new->set_available;
87
88
    $availability->set_unavailable("withdrawn") if $item->withdrawn;
89
    $availability->set_unavailable("itemlost") if $item->itemlost;
90
    $availability->set_unavailable("restricted") if $item->restricted;
91
92
    if ($item->damaged) {
93
        if (C4::Context->preference('AllowHoldsOnDamagedItems')) {
94
            $availability->add_description("damaged");
95
        } else {
96
            $availability->set_unavailable("damaged");
97
        }
98
    }
99
100
    my $itemtype;
101
    if (C4::Context->preference('item-level_itypes')) {
102
        $itemtype = Koha::ItemTypes->find($item->itype);
103
    } else {
104
        my $biblioitem = Koha::Biblioitems->find($item->biblioitemnumber );
105
        $itemtype = Koha::ItemTypes->find($biblioitem->itemtype);
106
    }
107
108
    if ($item->notforloan > 0 || $itemtype && $itemtype->notforloan) {
109
        $availability->set_unavailable("notforloan");
110
    } elsif ($item->notforloan < 0) {
111
        $availability->set_unavailable("ordered");
112
    }
113
114
    $self->{'_hold'} = $availability;
115
    return $availability;
116
}
117
118
=head3 issue
119
120
Availability for checkouts. Does not consider patron status.
121
122
=cut
123
124
sub issue {
125
    my ($self, $params) = @_;
126
127
    my $item = $self->item;
128
    my $availability;
129
    unless ($self->use_stored_values) {
130
        $availability = $self->hold->clone;
131
    }
132
    else {
133
        if ($self->{'_hold'}) {
134
            $availability = $self->{'_hold'}->clone;
135
        } else {
136
            $availability = $self->hold->clone;
137
        }
138
    }
139
140
    if (my $issue = Koha::Issues->find({ itemnumber => $item->itemnumber })) {
141
        $availability->set_unavailable("onloan", $issue->date_due);
142
    }
143
144
    if (C4::Reserves::CheckReserves($item->itemnumber)) {
145
        $availability->set_unavailable("reserved");
146
    }
147
148
    $self->{'_issue'} = $availability;
149
    return $availability;
150
}
151
152
=head3 item
153
154
=cut
155
156
sub item {
157
    my ($self) = @_;
158
159
    return $self->{'item'};
160
}
161
162
=head3 local_use
163
164
Same as checkout availability, but exclude notforloan.
165
166
=cut
167
168
sub local_use {
169
    my ($self) = @_;
170
171
    my $availability;
172
    unless ($self->use_stored_values) {
173
        $availability = $self->issue->clone;
174
    }
175
    else {
176
        if ($self->{'_issue'}) {
177
            $availability = $self->{'_issue'}->clone;
178
        } else {
179
            $availability = $self->issue->clone;
180
        }
181
    }
182
183
    if (grep(/^notforloan$/, @{$availability->description})
184
        && @{$availability->description} == 1) {
185
        $availability = $availability->set_available;
186
    }
187
    $availability->del_description("notforloan");
188
189
    $self->{'_local_use'} = $availability;
190
    return $availability;
191
}
192
193
=head3 onsite_checkout
194
195
Same as local_use availability, but consider OnSiteCheckouts system preference.
196
197
=cut
198
199
sub onsite_checkout {
200
    my ($self) = @_;
201
202
    my $availability;
203
    unless ($self->use_stored_values) {
204
        $availability = $self->local_use->clone;
205
    }
206
    else {
207
        if ($self->{'_local_use'}) {
208
            $availability = $self->{'_local_use'}->clone;
209
        } else {
210
            $availability = $self->local_use->clone;
211
        }
212
    }
213
214
    if (!C4::Context->preference('OnSiteCheckouts')) {
215
        $availability = Koha::Item::Availability->new
216
        ->set_unavailable("onsite_checkouts_disabled");
217
    }
218
219
    $self->{'_onsite_checkout'} = $availability;
220
    return $availability;
221
}
222
223
=head3 use_stored_values
224
225
ON: $availabilities->use_stored_values(1);
226
OFF: $availabilities->use_stored_values(0);
227
228
Performance enhancement.
229
230
Different availability types are dependent on some others. For example issues
231
are dependent on holds; if holds are unavailable, so are issues. If we want to
232
gather all types of availabilities in one go, we can store the previous
233
availability in the object and use it for the next one without re-calculating
234
the previous availabilities.
235
236
This is the purpose of this switch; when enabled, use stored availability in
237
the object for availability dependencies. When disabled, always re-calculate
238
dependencies as well.
239
240
=cut
241
242
sub use_stored_values {
243
    my ($self, $use_stored_values) = @_;
244
245
    if (defined $use_stored_values) {
246
        $self->{'_use_stored_values'} =
247
        $use_stored_values ? 1 : 0;
248
    }
249
250
    return $self->{'_use_stored_values'};
251
}
252
253
1;
(-)a/Koha/Item/Availability.pm (+282 lines)
Line 0 Link Here
1
package Koha::Item::Availability;
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 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 'Koha::Item::Availabilities'
33
  # ref($availabilities->issue) eq 'Koha::Item::Availability'
34
35
  print "Available for checkout!" if $availabilities->issue->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 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 has_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 set_available
188
189
$availability->set_available;
190
191
Sets the Koha::Item::Availability object status to available.
192
   $availability->available == 1
193
194
Overrides old availability status, but does not override other stored data in
195
the object. Create a new Koha::Item::Availability object to get a fresh start.
196
Appends any previously defined availability descriptions with add_description().
197
198
Returns updated Koha::Item::Availability object.
199
200
=cut
201
202
sub set_available {
203
    my ($self, $description) = @_;
204
205
    return $self->_update_availability_status(1, 0, $description);
206
}
207
208
=head3 set_needs_confirmation
209
210
$availability->set_needs_confirmation("unbelieveable_reason", "2016-07-07");
211
212
Sets the Koha::Item::Availability object status to unavailable,
213
but needs confirmation.
214
   $availability->available == 0
215
   $availability->availability_needs_confirmation == 1
216
217
Overrides old availability statuses, but does not override other stored data in
218
the object. Create a new Koha::Item::Availability object to get a fresh start.
219
Appends any previously defined availability descriptions with add_description().
220
Allows you to define expected availability date in C<$expected>.
221
222
Returns updated Koha::Item::Availability object.
223
224
=cut
225
226
sub set_needs_confirmation {
227
    my ($self, $description, $expected) = @_;
228
229
    return $self->_update_availability_status(0, 1, $description, $expected);
230
}
231
232
=head3 set_unavailable
233
234
$availability->set_unavailable("onloan", "2016-07-07");
235
236
Sets the Koha::Item::Availability object status to unavailable.
237
   $availability->available == 0
238
239
Overrides old availability status, but does not override other stored data in
240
the object. Create a new Koha::Item::Availability object to get a fresh start.
241
Appends any previously defined availability descriptions with add_description().
242
Allows you to define expected availability date in C<$expected>.
243
244
Returns updated Koha::Item::Availability object.
245
246
=cut
247
248
sub set_unavailable {
249
    my ($self, $description, $expected) = @_;
250
251
    return $self->_update_availability_status(0, 0, $description, $expected);
252
}
253
254
sub AUTOLOAD {
255
    my ($self, $params) = @_;
256
257
    my $method = our $AUTOLOAD;
258
    $method =~ s/.*://;
259
260
    # get & set
261
    if (exists $self->{$method}) {
262
        unless (defined $params) {
263
            return $self->{$method};
264
        } else {
265
            $self->{$method} = $params;
266
            return $self;
267
        }
268
    }
269
}
270
271
sub _update_availability_status {
272
    my ($self, $available, $needs, $desc, $expected) = @_;
273
274
    $self->available($available);
275
    $self->availability_needs_confirmation($needs);
276
    $self->expected_available($expected) if $expected;
277
    $self->add_description($desc);
278
279
    return $self;
280
}
281
282
1;
(-)a/t/db_dependent/Koha/Item/Availability.t (-1 / +250 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/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
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 => 4;
22
use t::lib::Mocks;
23
use t::lib::TestBuilder;
24
25
use C4::Biblio;
26
use C4::Circulation;
27
use C4::Reserves;
28
29
use Koha::Database;
30
use Koha::Items;
31
use Koha::ItemTypes;
32
33
use_ok('Koha::Item::Availabilities');
34
use_ok('Koha::Item::Availability');
35
36
my $schema = Koha::Database->new->schema;
37
$schema->storage->txn_begin;
38
39
subtest 'Koha::Item::Availability tests' => sub {
40
    plan tests => 14;
41
42
    my $availability = Koha::Item::Availability->new->set_available;
43
44
    is($availability->available, 1, "Available");
45
    $availability->set_needs_confirmation;
46
    is($availability->availability_needs_confirmation, 1, "Needs confirmation");
47
    $availability->set_unavailable;
48
    is($availability->available, 0, "Not available");
49
50
    $availability->add_description("such available");
51
    $availability->add_description("wow");
52
    $availability->add_description("wow");
53
54
    ok($availability->has_description("wow"), "Found description 'wow'");
55
    ok($availability->has_description(["wow", "such available"]),
56
       "Found description 'wow' and 'such available'");
57
    is($availability->has_description(["wow", "much not found"]), 0,
58
       "Didn't find 'wow' and 'much not found'");
59
    is($availability->description->[0], "such available",
60
       "Found correct description in correct index 1/4");
61
    is($availability->description->[1], "wow",
62
       "Found correct description in correct index 2/2");
63
64
    $availability->add_description(["much description", "very doge"]);
65
    is($availability->description->[2], "much description",
66
       "Found correct description in correct index 3/4");
67
    is($availability->description->[3], "very doge",
68
       "Found correct description in correct index 4/4");
69
70
    $availability->del_description("wow");
71
    is($availability->description->[1], "much description",
72
       "Found description from correct index after del");
73
    $availability->del_description(["very doge", "such available"]);
74
    is($availability->description->[0], "much description",
75
       "Found description from correct index after del");
76
77
    my $availability_clone = $availability;
78
    $availability->set_unavailable;
79
    is($availability_clone->available, $availability->{available},
80
       "Availability_clone points to availability");
81
    $availability_clone = $availability->clone;
82
    $availability->set_available;
83
    isnt($availability_clone->available, $availability->{available},
84
         "Availability_clone was cloned and no longer has same availability status");
85
};
86
87
subtest 'Item availability tests' => sub {
88
    plan tests => 14;
89
90
    my $builder = t::lib::TestBuilder->new;
91
    my $library = $builder->build({ source => 'Branch' });
92
    my $itemtype_built = $builder->build({
93
        source => 'Itemtype',
94
        value => {
95
            notforloan => 0,
96
        }
97
    });
98
    my $biblioitem_built = $builder->build({
99
        source => 'Biblioitem',
100
        value => {
101
            itemtype => $itemtype_built->{'itemtype'},
102
        }
103
    });
104
    my $item_built    = $builder->build({
105
        source => 'Item',
106
        value => {
107
            holding_branch => $library->{branchcode},
108
            homebranch => $library->{branchcode},
109
            biblioitemnumber => $biblioitem_built->{biblioitemnumber},
110
            itype => $itemtype_built->{itemtype},
111
        }
112
    });
113
114
    t::lib::Mocks::mock_preference('item-level_itypes', 0);
115
    t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
116
    t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 0);
117
118
    my $itemtype = Koha::ItemTypes->find($itemtype_built->{itemtype});
119
    my $item = Koha::Items->find($item_built->{itemnumber});
120
    $item->set({
121
        notforloan => 0,
122
        damaged => 0,
123
        itemlost => 0,
124
        withdrawn => 0,
125
        onloan => undef,
126
        restricted => 0,
127
    })->store; # set available
128
    
129
    ok($item->can('availabilities'), "Koha::Item->availabilities exists.");
130
    my $availabilities = $item->availabilities;
131
    is(ref($availabilities), 'Koha::Item::Availabilities', '$availabilities is blessed as Koha::Item::Availabilities');
132
133
    my $holdability = $availabilities->hold;
134
    my $issuability = $availabilities->issue;
135
    my $for_local_use = $availabilities->local_use;
136
    my $onsite_issuability = $availabilities->onsite_checkout;
137
    is(ref($holdability), 'Koha::Item::Availability', '1/4 Correct class');
138
    is(ref($issuability), 'Koha::Item::Availability', '2/4 Correct class');
139
    is(ref($for_local_use), 'Koha::Item::Availability', '3/4 Correct class');
140
    is(ref($onsite_issuability), 'Koha::Item::Availability', '4/4 Correct class');
141
142
    ok($holdability->available, 'Available for holds');
143
    ok($issuability->available, 'Available for checkouts');
144
    ok($for_local_use->available, 'Available for local use');
145
    ok($onsite_issuability->available, 'Available for onsite checkout');
146
147
    # Test plan:
148
    # Subtest for each availability type in predefined order;
149
    # hold -> checkout -> local_use -> onsite_checkout
150
    # Each is dependant on the previous one, no need to run same tests as moving
151
    # from left to right.
152
    subtest 'Availability: hold' => sub {
153
        plan tests => 14;
154
155
        $item->withdrawn(1)->store;
156
        ok(!$availabilities->hold->available, "Item withdrawn => not available");
157
        is($availabilities->hold->description->[0], 'withdrawn', 'Description: withdrawn');
158
        $item->withdrawn(0)->itemlost(1)->store;
159
        ok(!$availabilities->hold->available, "Item lost => not available");
160
        is($availabilities->hold->description->[0], 'itemlost', 'Description: itemlost');
161
        $item->itemlost(0)->restricted(1)->store;
162
        ok(!$availabilities->hold->available, "Item restricted => not available");
163
        is($availabilities->hold->description->[0], 'restricted', 'Description: restricted');
164
        $item->restricted(0)->store;
165
166
        subtest 'Hold on damaged item' => sub {
167
            plan tests => 3;
168
169
            t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 0);
170
            $item->damaged(1)->store;
171
            ok($item->damaged, "Item is damaged");
172
            ok(!$availabilities->hold->available, 'Not available for holds (AllowHoldsOnDamagedItems => 0)');
173
            t::lib::Mocks::mock_preference('AllowHoldsOnDamagedItems', 1);
174
            ok($availabilities->hold->available, 'Available for holds (AllowHoldsOnDamagedItems => 1)');
175
            $item->damaged(0)->store;
176
        };
177
178
        t::lib::Mocks::mock_preference('item-level_itypes', 1);
179
        $item->notforloan(1)->store;
180
        ok(!$availabilities->hold->available, "Item notforloan => not available");
181
        is($availabilities->hold->description->[0], 'notforloan', 'Description: notforloan');
182
        t::lib::Mocks::mock_preference('item-level_itypes', 0);
183
        $item->notforloan(0)->store;
184
        $itemtype->notforloan(1)->store;
185
        ok(!$availabilities->hold->available, "Itemtype notforloan => not available");
186
        is($availabilities->hold->description->[0], 'notforloan', 'Description: notforloan');
187
        $itemtype->notforloan(0)->store;
188
        ok($availabilities->hold->available, "Available");
189
        $item->notforloan(-1)->store;
190
        ok(!$availabilities->hold->available, "Itemtype notforloan -1 => not available");
191
        is($availabilities->hold->description->[0], 'ordered', 'Description: ordered');
192
        $item->notforloan(0)->store;
193
    };
194
195
    subtest 'Availability: Checkout' => sub {
196
        plan tests => 7;
197
198
        my $patron = $builder->build({ source => 'Borrower' });
199
        my $biblio = C4::Biblio::GetBiblio($item->biblionumber);
200
        my $priority= C4::Reserves::CalculatePriority( $item->biblionumber );
201
        my $reserve_id = C4::Reserves::AddReserve(
202
            $item->holdingbranch,
203
            $patron->{borrowernumber},
204
            $item->biblionumber,
205
            undef,
206
            $priority,
207
            undef, undef, undef,
208
            $$biblio{title},
209
            $item->itemnumber,
210
            undef
211
        );
212
213
        ok(!$availabilities->issue->available, "Item reserved => not available");
214
        is($availabilities->issue->description->[0], 'reserved', 'Description: reserved');
215
        C4::Reserves::CancelReserve({ reserve_id => $reserve_id });
216
        ok($availabilities->issue->available, "Reserve cancelled => available");
217
218
        my $module = new Test::MockModule('C4::Context');
219
        $module->mock( 'userenv', sub { { branch => $patron->{branchcode} } } );
220
        my $issue = C4::Circulation::AddIssue($patron, $item->barcode, undef, 1);
221
        ok(!$availabilities->issue->available, "Item issued => not available");
222
        is($availabilities->issue->description->[0], 'onloan', 'Description: onloan');
223
        is($availabilities->issue->expected_available,
224
           $issue->date_due, "Expected to be available '".$issue->date_due."'");
225
        C4::Circulation::AddReturn($item->barcode, $item->homebranch);
226
        ok($availabilities->issue->available, "Checkin => available");
227
    };
228
229
    subtest 'Availability: Local use' => sub {
230
        plan tests => 1;
231
232
        $item->notforloan(1)->store;
233
        ok($availabilities->local_use->available, "Item notforloan => available");
234
    };
235
236
    subtest 'Availability: On-site checkout' => sub {
237
        plan tests => 2;
238
239
        t::lib::Mocks::mock_preference('OnSiteCheckouts', 0);
240
        ok(!$availabilities->onsite_checkout->available, 'Not available for onsite checkout '
241
           .'(OnSiteCheckouts => 0)');
242
        t::lib::Mocks::mock_preference('OnSiteCheckouts', 1);
243
        ok($availabilities->onsite_checkout->available, 'Available for onsite checkout '
244
           .'(OnSiteCheckouts => 1)');
245
    };
246
};
247
248
$schema->storage->txn_rollback;
249
250
1;

Return to bug 16826