Bug 32030: Add documents to license
[koha.git] / Koha / Holds.pm
1 package Koha::Holds;
2
3 # Copyright ByWater Solutions 2014
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
22
23 use Koha::Database;
24
25 use Koha::Hold;
26
27 use base qw(Koha::Objects);
28
29 =head1 NAME
30
31 Koha::Holds - Koha Hold object set class
32
33 =head1 API
34
35 =head2 Class methods
36
37 =cut
38
39 =head3 waiting
40
41 returns a set of holds that are waiting from an existing set
42
43 =cut
44
45 sub waiting {
46     my ( $self ) = @_;
47
48     return $self->search( { found => 'W' } );
49 }
50
51 =head3 processing
52
53 returns a set of holds that are processing from an existing set
54
55 =cut
56
57 sub processing {
58     my ( $self ) = @_;
59
60     return $self->search( { found => 'P' } );
61 }
62
63 =head3 unfilled
64
65 returns a set of holds that are unfilled from an existing set
66
67 =cut
68
69 sub unfilled {
70     my ( $self ) = @_;
71
72     return $self->search( { found => undef } );
73 }
74
75 =head3 forced_hold_level
76
77 If a patron has multiple holds for a single record,
78 those holds must be either all record level holds,
79 or they must all be item level holds.
80
81 This method should be used with Hold sets where all
82 Hold objects share the same patron and record.
83
84 This method will return 'item' if the patron has
85 at least one item level hold. It will return 'record'
86 if the patron has holds but none are item level,
87 Finally, if the patron has no holds, it will return
88 undef which indicates the patron may select either
89 record or item level holds, barring any other rules
90 that would prevent one or the other.
91
92 =cut
93
94 sub forced_hold_level {
95     my ($self) = @_;
96
97     my $item_level_count = $self->search( { itemnumber => { '!=' => undef } } )->count();
98     return 'item' if $item_level_count > 0;
99
100     my $item_group_level_count = $self->search( { item_group_id => { '!=' => undef } } )->count();
101     return 'item_group' if $item_group_level_count > 0;
102
103     my $record_level_count = $self->search( { itemnumber => undef } )->count();
104     return 'record' if $record_level_count > 0;
105
106     return;
107 }
108
109 =head3 get_items_that_can_fill
110
111     my $items = $holds->get_items_that_can_fill();
112
113 Return the list of items that can fill the hold set.
114
115 Items that are not:
116
117   in transit
118   waiting
119   lost
120   widthdrawn
121   not for loan
122   not on loan
123
124 =cut
125
126 sub get_items_that_can_fill {
127     my ( $self ) = @_;
128
129     return Koha::Items->new->empty()
130       unless $self->count() > 0;
131
132     my @itemnumbers = $self->search({ 'me.itemnumber' => { '!=' => undef } })->get_column('itemnumber');
133     my @biblionumbers = $self->search({ 'me.itemnumber' => undef })->get_column('biblionumber');
134     my @bibs_or_items;
135     push @bibs_or_items, 'me.itemnumber' => { in => \@itemnumbers } if @itemnumbers;
136     push @bibs_or_items, 'me.biblionumber' => { in => \@biblionumbers } if @biblionumbers;
137
138     my @branchtransfers = Koha::Item::Transfers->filter_by_current->search({}, {
139             columns  => ['itemnumber'],
140             collapse => 1,
141         }
142     )->get_column('itemnumber');
143     my @waiting_holds = Koha::Holds->search(
144         { 'found' => 'W' },
145         {
146             columns  => ['itemnumber'],
147             collapse => 1,
148         }
149     )->get_column('itemnumber');
150
151     return Koha::Items->search(
152         {
153             -or => \@bibs_or_items,
154             itemnumber   => { -not_in => [ @branchtransfers, @waiting_holds ] },
155             onloan       => undef,
156             notforloan   => 0,
157         }
158     )->filter_by_for_hold();
159 }
160
161 =head3 filter_by_has_cancellation_requests
162
163     my $with_cancellation_reqs = $holds->filter_by_has_cancellation_requests;
164
165 Returns a filtered resultset only containing holds that have cancellation requests.
166
167 =cut
168
169 sub filter_by_has_cancellation_requests {
170     my ($self) = @_;
171
172     return $self->search( { 'hold_cancellation_request_id' => { '!=' => undef } },
173         { join => 'cancellation_requests' } );
174 }
175
176 =head3 filter_out_has_cancellation_requests
177
178     my $holds_without_cancellation_requests = $holds->filter_out_has_cancellation_requests;
179
180 Returns a filtered resultset without holds with cancellation requests.
181
182 =cut
183
184 sub filter_out_has_cancellation_requests {
185     my ($self) = @_;
186
187     return $self->search( { 'hold_cancellation_request_id' => { '=' => undef } },
188         { join => 'cancellation_requests' } );
189 }
190
191 =head2 Internal methods
192
193 =head3 _type
194
195 =cut
196
197 sub _type {
198     return 'Reserve';
199 }
200
201 =head3 object_class
202
203 =cut
204
205 sub object_class {
206     return 'Koha::Hold';
207 }
208
209 =head1 AUTHOR
210
211 Kyle M Hall <kyle@bywatersolutions.com>
212
213 =cut
214
215 1;