Bug 30650: Allow to restrict curbside pickup for waiting holds only
[koha.git] / t / db_dependent / Koha / CurbsidePickups.t
1 #!/usr/bin/perl
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 Test::More tests => 4;
21 use Test::Exception;
22
23 use Koha::City;
24 use Koha::CurbsidePickups;
25 use Koha::CurbsidePickupPolicies;
26 use Koha::Database;
27 use Koha::DateUtils qw( dt_from_string );
28
29 use t::lib::TestBuilder;
30 use t::lib::Dates;
31 use t::lib::Mocks;
32
33 my $schema = Koha::Database->new->schema;
34 $schema->storage->txn_begin;
35
36 my $builder          = t::lib::TestBuilder->new;
37 my $library          = $builder->build_object( { class => 'Koha::Libraries' } );
38 my $library_disabled = $builder->build_object( { class => 'Koha::Libraries' } );
39 my $logged_in_patron = $builder->build_object(
40     {
41         class => 'Koha::Patrons',
42         value => { branchcode => $library->branchcode }
43     }
44 );
45 t::lib::Mocks::mock_userenv( { patron => $logged_in_patron } );
46 my $patron = $builder->build_object(
47     {
48         class => 'Koha::Patrons',
49         value => { branchcode => $library->branchcode }
50     }
51 );
52
53 my $policy = Koha::CurbsidePickupPolicy->new(
54     {
55         branchcode              => $library->branchcode,
56         enabled                 => 1,
57         enable_waiting_holds_only => 0,
58         pickup_interval         => 30,
59         patrons_per_interval    => 2,
60         patron_scheduled_pickup => 1
61     }
62 )->store;
63 my $policy_disabled = Koha::CurbsidePickupPolicy->new(
64     {
65         branchcode              => $library_disabled->branchcode,
66         enabled                 => 0,
67         enable_waiting_holds_only => 0,
68         pickup_interval         => 30,
69         patrons_per_interval    => 2,
70         patron_scheduled_pickup => 1
71     }
72 )->store;
73
74 # Open Mondays from 12 to 18
75 $policy->add_opening_slot('1-12:00-18:00');
76
77 my $today = dt_from_string;
78
79 subtest 'Create a pickup' => sub {
80     plan tests => 7;
81
82     # Day and datetime are ok
83     my $next_monday =
84       $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 );
85     my $schedule_dt =
86       $next_monday->set_hour(15)->set_minute(00)->set_second(00);
87     my $params =
88         {
89             branchcode                => $library->branchcode,
90             borrowernumber            => $patron->borrowernumber,
91             scheduled_pickup_datetime => $schedule_dt,
92             notes                     => 'just a note'
93         };
94
95     throws_ok {
96         Koha::CurbsidePickup->new({%$params, branchcode => $library_disabled->branchcode})->store;
97     }
98     'Koha::Exceptions::CurbsidePickup::NotEnabled',
99       'Cannot create pickup if the policy does not allow it';
100
101     $policy->enable_waiting_holds_only(1)->store;
102     throws_ok {
103         Koha::CurbsidePickup->new($params)->store;
104     }
105     'Koha::Exceptions::CurbsidePickup::NoWaitingHolds',
106       'Cannot create pickup for a patron without waiting hold if flag is set';
107
108     $policy->enable_waiting_holds_only(0)->store;
109     my $cp = Koha::CurbsidePickup->new($params)->store;
110     is( $cp->status, 'to-be-staged' );
111
112     throws_ok {
113         Koha::CurbsidePickup->new($params)->store
114     }
115     'Koha::Exceptions::CurbsidePickup::TooManyPickups',
116       'Cannot create 2 pickups for the same patron';
117
118     $cp->delete;
119
120     # Day is not ok
121     my $next_tuesday =
122       $today->clone->add( days => ( 2 - $today->day_of_week ) % 7 );
123     $schedule_dt = $next_tuesday->set_hour(15)->set_minute(00)->set_second(00);
124     throws_ok {
125         Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store;
126     }
127     'Koha::Exceptions::CurbsidePickup::NoMatchingSlots',
128       'Cannot create a pickup on a day without opening slots defined';
129
130     # Day ok but datetime not ok
131     $schedule_dt = $next_monday->set_hour(19)->set_minute(00)->set_second(00);
132     throws_ok {
133         Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store;
134     }
135     'Koha::Exceptions::CurbsidePickup::NoMatchingSlots',
136       'Cannot create a pickup on a time without opening slots defined';
137
138     # Day ok, datetime inside the opening slot, but wrong (15:15 for instance)
139     $schedule_dt = $next_monday->set_hour(15)->set_minute(15)->set_second(00);
140     throws_ok {
141         Koha::CurbsidePickup->new({%$params, scheduled_pickup_datetime => $schedule_dt})->store;
142     }
143     'Koha::Exceptions::CurbsidePickup::NoMatchingSlots',
144 'Cannot create a pickup on a time that is not matching the start of an interval';
145
146 };
147
148 subtest 'workflow' => sub {
149     plan tests => 9;
150
151     my $pickups =
152       Koha::CurbsidePickups->search( { branchcode => $library->branchcode } );
153
154     my $next_monday =
155       $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 );
156     my $schedule_dt =
157       $next_monday->set_hour(15)->set_minute(00)->set_second(00);
158     my $cp = Koha::CurbsidePickup->new(
159         {
160             branchcode                => $library->branchcode,
161             borrowernumber            => $patron->borrowernumber,
162             scheduled_pickup_datetime => $schedule_dt,
163             notes                     => 'just a note'
164         }
165     )->store;
166     is( $cp->status, 'to-be-staged' );
167     is( $pickups->filter_by_to_be_staged->count, 1 );
168
169     $cp->mark_as_staged;
170     is( $cp->status, 'staged-and-ready' );
171     is( $pickups->filter_by_staged_and_ready->count, 1 );
172
173     $cp->mark_as_unstaged;
174     is( $cp->status, 'to-be-staged' );
175
176     $cp->mark_as_staged;
177
178     $cp->mark_patron_has_arrived;
179     is( $cp->status, 'patron-is-outside' );
180     is( $pickups->filter_by_patron_outside->count, 1 );
181
182     $cp->mark_as_delivered;
183     is( $cp->status, 'delivered' );
184     is( $pickups->filter_by_delivered->count, 1 );
185
186     $cp->delete;
187 };
188
189 subtest 'mark_as_delivered' => sub {
190     plan tests => 3;
191
192     my $item = $builder->build_sample_item({ library => $library->branchcode });
193     my $reserve_id = C4::Reserves::AddReserve(
194         {
195             branchcode     => $library->branchcode,
196             borrowernumber => $patron->borrowernumber,
197             biblionumber   => $item->biblionumber,
198             priority       => 1,
199             itemnumber     => $item->itemnumber,
200         }
201     );
202     my $hold = Koha::Holds->find($reserve_id);
203     $hold->set_waiting;
204
205     my $next_monday =
206       $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 );
207     my $schedule_dt =
208       $next_monday->set_hour(15)->set_minute(00)->set_second(00);
209     my $cp = Koha::CurbsidePickup->new(
210         {
211             branchcode                => $library->branchcode,
212             borrowernumber            => $patron->borrowernumber,
213             scheduled_pickup_datetime => $schedule_dt,
214             notes                     => 'just a note'
215         }
216     )->store;
217
218     $cp->mark_as_delivered;
219     $cp->discard_changes;
220     is( t::lib::Dates::compare( $cp->arrival_datetime, dt_from_string), 0, 'Arrival time has been set to now' );
221
222     is( $hold->get_from_storage, undef, 'Hold has been filled' );
223     my $checkout = Koha::Checkouts->find({ itemnumber => $item->itemnumber });
224     is( $checkout->borrowernumber, $patron->borrowernumber, 'Item has correctly been checked out' );
225
226     $cp->delete;
227 };
228
229 subtest 'notify_new_pickup' => sub {
230     plan tests => 2;
231
232     my $item =
233       $builder->build_sample_item( { library => $library->branchcode } );
234     my $reserve_id = C4::Reserves::AddReserve(
235         {
236             branchcode     => $library->branchcode,
237             borrowernumber => $patron->borrowernumber,
238             biblionumber   => $item->biblionumber,
239             priority       => 1,
240             itemnumber     => $item->itemnumber,
241         }
242     );
243     my $hold = Koha::Holds->find($reserve_id);
244     $hold->set_waiting;
245
246     my $next_monday =
247       $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 );
248     my $schedule_dt =
249       $next_monday->set_hour(15)->set_minute(00)->set_second(00);
250     my $cp = Koha::CurbsidePickup->new(
251         {
252             branchcode                => $library->branchcode,
253             borrowernumber            => $patron->borrowernumber,
254             scheduled_pickup_datetime => $schedule_dt,
255             notes                     => 'just a note'
256         }
257     )->store;
258
259     $patron->set( { email => 'test@example.org' } )->store;
260     my $dbh = C4::Context->dbh;
261     $dbh->do( q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ?)|,
262         undef, $patron->borrowernumber, 4
263     );
264     my $borrower_message_preference_id =
265       $dbh->last_insert_id( undef, undef, "borrower_message_preferences", undef );
266     $dbh->do(
267         q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|,
268         undef, $borrower_message_preference_id, 'email'
269     );
270
271     $cp->notify_new_pickup;
272
273     my $messages = C4::Letters::GetQueuedMessages(
274         { borrowernumber => $patron->borrowernumber } );
275     is(
276         $messages->[0]->{subject},
277         sprintf ("You have schedule a curbside pickup for %s.", $library->branchname),
278         "Notice correctly generated"
279     );
280     my $biblio_title = $item->biblio->title;
281     like( $messages->[0]->{content},
282         qr{$biblio_title}, "Content contains the list of waiting holds" );
283 };
284
285 $schema->storage->txn_rollback;