Bug 30650: Add some useful modules and tests
[koha.git] / Koha / CurbsidePickup.pm
1 package Koha::CurbsidePickup;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use Carp;
21
22 use Koha::Database;
23
24 use base qw(Koha::Object);
25
26 use C4::Circulation qw( CanBookBeIssued AddIssue );
27 use Koha::DateUtils qw( dt_from_string );
28 use Koha::Patron;
29 use Koha::Library;
30 use Koha::CurbsidePickupIssues;
31 use Koha::Exceptions::CurbsidePickup;
32
33 =head1 NAME
34
35 Koha::CurbsidePickup - Koha Curbside Pickup Object class
36
37 =head1 API
38
39 =head2 Class methods
40
41 =cut
42
43 =head3 new
44
45 =cut
46
47 sub new {
48     my ( $self, $params ) = @_;
49
50     my $existing_curbside_pickups = Koha::CurbsidePickups->search(
51         {
52             branchcode                => $params->{branchcode},
53             borrowernumber            => $params->{borrowernumber},
54             delivered_datetime        => undef,
55             scheduled_pickup_datetime => { '>' => \'DATE(NOW())' },
56         }
57     );
58     Koha::Exceptions::CurbsidePickup::TooManyPickups->throw(
59         branchcode     => $params->{branchcode},
60         borrowernumber => $params->{borrowernumber}
61     ) if $existing_curbside_pickups->count;
62
63     my $policy =
64       Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } );
65     my $is_valid =
66       $policy->is_valid_pickup_datetime( $params->{scheduled_pickup_datetime} );
67     unless ($is_valid) {
68         my $error = @{ $is_valid->messages }[0]->message;
69         Koha::Exceptions::CurbsidePickup::NoMatchingSlots->throw
70           if $error eq 'no_matching_slots';
71         Koha::Exceptions::CurbsidePickup::NoMorePickupsAvailable->throw
72           if $error eq 'no_more_available';
73         Koha::Exceptions->throw(
74             "Error message must raise the appropriate exception");
75     }
76
77     return $self->SUPER::new($params);
78 }
79
80 =head3 checkouts
81
82 Return the checkouts linked to this pickup
83
84 =cut
85
86 sub checkouts {
87     my ( $self ) = @_;
88
89     my @pi = Koha::CurbsidePickupIssues->search({ curbside_pickup_id => $self->id })->as_list;
90
91     my @checkouts = map { $_->checkout } @pi;
92     @checkouts = grep { defined $_ } @checkouts;
93
94     return @checkouts;
95 }
96
97 =head3 patron
98
99 Return the patron linked to this pickup
100
101 =cut
102
103 sub patron {
104     my ( $self ) = @_;
105     my $rs = $self->_result->borrowernumber;
106     return unless $rs;
107     return Koha::Patron->_new_from_dbic( $rs );
108 }
109
110 =head3 staged_by_staff
111
112 Return the staff member that staged this pickup
113
114 =cut
115
116 sub staged_by_staff {
117     my ( $self ) = @_;
118     my $rs = $self->_result->staged_by;
119     return unless $rs;
120     return Koha::Patron->_new_from_dbic( $rs );
121 }
122
123 =head3 library
124
125 Return the branch associated with this pickup
126
127 =cut
128
129 sub library {
130     my ( $self ) = @_;
131     my $rs = $self->_result->branchcode;
132     return unless $rs;
133     return Koha::Library->_new_from_dbic( $rs );
134 }
135
136 =head3 mark_as_staged
137
138 Mark the pickup as staged
139
140 =cut
141
142 sub mark_as_staged {
143     my ( $self ) = @_;
144     my $staged_by = C4::Context->userenv ? C4::Context->userenv->{number} : undef;
145     $self->set(
146         {
147             staged_datetime  => dt_from_string(),
148             staged_by        => $staged_by,
149             arrival_datetime => undef,
150         }
151     )->store;
152 }
153
154 =head3 mark_as_unstaged
155
156 Mark the pickup as unstaged
157
158 =cut
159
160 sub mark_as_unstaged {
161     my ( $self ) = @_;
162
163     $self->set(
164         {
165             staged_datetime  => undef,
166             staged_by        => undef,
167             arrival_datetime => undef,
168         }
169     )->store;
170 }
171
172 =head3 mark_patron_has_arrived
173
174 Set the arrival time of the patron
175
176 =cut
177
178 sub mark_patron_has_arrived {
179     my ( $self ) = @_;
180     $self->set(
181         {
182             arrival_datetime => dt_from_string(),
183         }
184     )->store;
185 }
186
187 =head3 mark_as_delivered
188
189 Mark the pickup as delivered. The waiting holds will be filled.
190
191 =cut
192
193 sub mark_as_delivered {
194     my ( $self ) = @_;
195     my $patron          = $self->patron;
196     my $holds           = $patron->holds;
197     my $branchcode = C4::Context->userenv ? C4::Context->userenv->{branch} : undef;
198     foreach my $hold ( $holds->as_list ) {
199         if ( $hold->found eq 'W' && $branchcode && $hold->branchcode eq $branchcode ) {
200             my ( $issuingimpossible, $needsconfirmation ) =
201               C4::Circulation::CanBookBeIssued( $patron, $hold->item->barcode );
202
203             unless ( keys %$issuingimpossible ) {
204                 my $issue =
205                   C4::Circulation::AddIssue( $patron->unblessed, $hold->item->barcode );
206                 if ($issue) {
207                     Koha::CurbsidePickupIssue->new(
208                         {
209                             curbside_pickup_id => $self->id,
210                             issue_id           => $issue->id,
211                             reserve_id         => $hold->id,
212                         }
213                     )->store();
214                 }
215                 else {
216                     Koha::Exceptions->throw(sprintf("Cannot checkout hold %s for patron %s: %s", $patron->id, $hold->id, join(", ", keys %$issuingimpossible)));
217                 }
218             }
219         }
220     }
221
222     my $delivered_by = C4::Context->userenv ? C4::Context->userenv->{number} : undef;
223     $self->arrival_datetime(dt_from_string) unless $self->arrival_datetime;
224     $self->set(
225         {
226             delivered_datetime => dt_from_string(),
227             delivered_by       => $delivered_by,
228         }
229     )->store;
230 }
231
232 =head3 status
233
234 Return the status of the pickup, can be 'to-be-staged', 'staged-and-ready', 'patron-is-outside' or 'delivered'.
235
236 =cut
237
238 sub status {
239     my ($self) = @_;
240     return
241         !defined $self->staged_datetime    ? 'to-be-staged'
242       : !defined $self->arrival_datetime   ? 'staged-and-ready'
243       : !defined $self->delivered_datetime ? 'patron-is-outside'
244       :                                      'delivered';
245 }
246
247 =head2 Internal methods
248
249 =head3 _type
250
251 =cut
252
253 sub _type {
254     return 'CurbsidePickup';
255 }
256
257 1;