a28cc48f925d070c61bb5c92476e6b29c480ca4d
[srvgit] / t / db_dependent / Koha / Charges / Fees.t
1 #!/usr/bin/perl
2 #
3 # Copyright 2018 ByWater Solutions
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 use Test::More tests => 8;
23 use Test::Exception;
24 use Test::Warn;
25
26 use t::lib::Mocks;
27 use t::lib::TestBuilder;
28
29 use Time::Fake;
30 use C4::Calendar;
31 use Koha::DateUtils qw(dt_from_string);
32
33 BEGIN {
34     use_ok('Koha::Charges::Fees');
35 }
36
37 my $schema  = Koha::Database->new->schema;
38 my $builder = t::lib::TestBuilder->new();
39 $schema->storage->txn_begin;
40
41 my $patron_category = $builder->build_object(
42     {
43         class => 'Koha::Patron::Categories',
44         value => {
45             category_type => 'P',
46             enrolmentfee  => 0,
47         }
48     }
49 );
50 my $library = $builder->build_object(
51     {
52         class => 'Koha::Libraries',
53     }
54 );
55 my $biblio = $builder->build_object(
56     {
57         class => 'Koha::Biblios',
58     }
59 );
60 my $itemtype = $builder->build_object(
61     {
62         class => 'Koha::ItemTypes',
63         value => {
64             rentalcharge_daily           => '0.00',
65             rentalcharge_daily_calendar  => 1,
66             rentalcharge_hourly          => '0.00',
67             rentalcharge_hourly_calendar => 1,
68             rentalcharge                 => '0.00',
69             processfee                   => '0.00',
70             defaultreplacecost           => '0.00',
71           },
72     }
73 );
74 my $item = $builder->build_object(
75     {
76         class => 'Koha::Items',
77         value => {
78             biblionumber  => $biblio->id,
79             homebranch    => $library->id,
80             holdingbranch => $library->id,
81             itype         => $itemtype->id,
82         }
83     }
84 );
85 my $patron = $builder->build_object(
86     {
87         class => 'Koha::Patrons',
88         value => {
89             dateexpiry   => '9999-12-31',
90             categorycode => $patron_category->id,
91         }
92     }
93 );
94
95 my $now = dt_from_string()->set_time_zone('floating');
96 Time::Fake->offset( $now->epoch );
97
98 my $dt_from = $now->clone->subtract( days => 2 );
99 my $dt_to = $now->clone->add( days => 4 );
100
101 subtest 'new' => sub {
102     plan tests => 9;
103
104     # Mandatory parameters missing
105     throws_ok {
106         Koha::Charges::Fees->new(
107             {
108                 library => $library,
109                 item    => $item,
110                 to_date => $dt_to,
111             }
112           )
113     }
114     'Koha::Exceptions::MissingParameter', 'MissingParameter thrown for patron';
115     throws_ok {
116         Koha::Charges::Fees->new(
117             {
118                 patron  => $patron,
119                 item    => $item,
120                 to_date => $dt_to,
121             }
122           )
123     }
124     'Koha::Exceptions::MissingParameter', 'MissingParameter thrown for library';
125     throws_ok {
126         Koha::Charges::Fees->new(
127             {
128                 patron  => $patron,
129                 library => $library,
130                 to_date => $dt_to,
131             }
132           )
133     }
134     'Koha::Exceptions::MissingParameter', 'MissingParameter thrown for item';
135     throws_ok {
136         Koha::Charges::Fees->new(
137             {
138                 patron  => $patron,
139                 library => $library,
140                 item    => $item,
141             }
142           )
143     }
144     'Koha::Exceptions::MissingParameter', 'MissingParameter thrown for to_date';
145
146     # Mandatory parameter bad
147     dies_ok {
148         Koha::Charges::Fees->new(
149             {
150                 patron  => '12345',
151                 library => $library,
152                 item    => $item,
153                 to_date => $dt_to,
154             }
155           )
156     }
157     'dies for bad patron';
158     dies_ok {
159         Koha::Charges::Fees->new(
160             {
161                 patron  => $patron,
162                 library => '12345',
163                 item    => $item,
164                 to_date => $dt_to,
165             }
166           )
167     }
168     'dies for bad library';
169     dies_ok {
170         Koha::Charges::Fees->new(
171             {
172                 patron  => $patron,
173                 library => $library,
174                 item    => '12345',
175                 to_date => $dt_to,
176             }
177           )
178     }
179     'dies for bad item';
180     dies_ok {
181         Koha::Charges::Fees->new(
182             {
183                 patron  => $patron,
184                 library => $library,
185                 item    => $item,
186                 to_date => 12345
187             }
188           )
189     }
190     'dies for bad to_date';
191
192     # Defaults
193     my $fees = Koha::Charges::Fees->new(
194         {
195             patron  => $patron,
196             library => $library,
197             item    => $item,
198             to_date => $dt_to,
199         }
200     );
201     is( $fees->from_date, dt_from_string(),
202         'from_date default set correctly to today' );
203 };
204
205 subtest 'patron accessor' => sub {
206     plan tests => 2;
207
208     my $fees = Koha::Charges::Fees->new(
209         {
210             patron  => $patron,
211             library => $library,
212             item    => $item,
213             to_date => $dt_to,
214         }
215     );
216
217     ok(
218         $fees->patron->isa('Koha::Patron'),
219         'patron accessor returns a Koha::Patron'
220     );
221     warning_is { $fees->patron('12345') }
222     { carped =>
223 "Setting 'patron' to something other than a Koha::Patron is not supported!"
224     }, "Warning thrown when attempting to set patron to string";
225
226 };
227
228 subtest 'library accessor' => sub {
229     plan tests => 2;
230
231     my $fees = Koha::Charges::Fees->new(
232         {
233             patron  => $patron,
234             library => $library,
235             item    => $item,
236             to_date => $dt_to,
237         }
238     );
239
240     ok(
241         $fees->library->isa('Koha::Library'),
242         'library accessor returns a Koha::Library'
243     );
244     warning_is { $fees->library('12345') }
245     { carped =>
246 "Setting 'library' to something other than a Koha::Library is not supported!"
247     }, "Warning thrown when attempting to set library to string";
248 };
249
250 subtest 'item accessor' => sub {
251     plan tests => 2;
252
253     my $fees = Koha::Charges::Fees->new(
254         {
255             patron  => $patron,
256             library => $library,
257             item    => $item,
258             to_date => $dt_to,
259         }
260     );
261
262     ok( $fees->item->isa('Koha::Item'), 'item accessor returns a Koha::Item' );
263     warning_is { $fees->item('12345') }
264     { carped =>
265 "Setting 'item' to something other than a Koha::Item is not supported!"
266     }, "Warning thrown when attempting to set item to string";
267 };
268
269 subtest 'to_date accessor' => sub {
270     plan tests => 2;
271
272     my $fees = Koha::Charges::Fees->new(
273         {
274             patron  => $patron,
275             library => $library,
276             item    => $item,
277             to_date => $dt_to,
278         }
279     );
280
281     ok( $fees->to_date->isa('DateTime'),
282         'to_date accessor returns a DateTime' );
283     warning_is { $fees->to_date(12345) }
284     { carped =>
285 "Setting 'to_date' to something other than a DateTime is not supported!"
286     }, "Warning thrown when attempting to set to_date to integer";
287 };
288
289 subtest 'from_date accessor' => sub {
290     plan tests => 2;
291
292     my $fees = Koha::Charges::Fees->new(
293         {
294             patron  => $patron,
295             library => $library,
296             item    => $item,
297             to_date => $dt_to,
298         }
299     );
300
301     ok(
302         $fees->from_date->isa('DateTime'),
303         'from_date accessor returns a DateTime'
304     );
305     warning_is { $fees->from_date(12345) }
306     { carped =>
307 "Setting 'from_date' to something other than a DateTime is not supported!"
308     }, "Warning thrown when attempting to set from_date to integer";
309 };
310
311 subtest 'accumulate_rentalcharge tests' => sub {
312     plan tests => 9;
313
314     my $fees = Koha::Charges::Fees->new(
315         {
316             patron    => $patron,
317             library   => $library,
318             item      => $item,
319             to_date   => $dt_to,
320             from_date => $dt_from,
321         }
322     );
323
324     # Daily tests
325     Koha::CirculationRules->set_rules({
326             categorycode => $patron->categorycode,
327             itemtype     => $itemtype->id,
328             branchcode   => $library->id,
329             rules => {
330                 lengthunit => 'days',
331             }
332         }
333     );
334
335     $itemtype->rentalcharge_daily(1.00);
336     $itemtype->store();
337     is( $itemtype->rentalcharge_daily,
338         1.00, 'Daily return charge stored correctly' );
339
340     t::lib::Mocks::mock_preference( 'finesCalendar', 'ignoreCalendar' );
341     my $charge = $fees->accumulate_rentalcharge();
342     is( $charge, 6.00,
343 'Daily rental charge calculated correctly with finesCalendar = ignoreCalendar'
344     );
345
346     t::lib::Mocks::mock_preference( 'finesCalendar', 'noFinesWhenClosed' );
347     $charge = $fees->accumulate_rentalcharge();
348     is( $charge, 6.00,
349 'Daily rental charge calculated correctly with finesCalendar = noFinesWhenClosed'
350     );
351
352     $itemtype->rentalcharge_daily_calendar(0)->store();
353     $charge = $fees->accumulate_rentalcharge();
354     is( $charge, 6.00,
355 'Daily rental charge calculated correctly with finesCalendar = noFinesWhenClosed and rentalcharge_daily_calendar = 0'
356     );
357     $itemtype->rentalcharge_daily_calendar(1)->store();
358
359     my $calendar = C4::Calendar->new( branchcode => $library->id );
360     # DateTime 1..7 (Mon..Sun), C4::Calender 0..6 (Sun..Sat)
361     my $closed_day =
362         ( $dt_from->day_of_week == 6 ) ? 0
363       : ( $dt_from->day_of_week == 7 ) ? 1
364       :                                  $dt_from->day_of_week + 1;
365     $calendar->insert_week_day_holiday(
366         weekday     => $closed_day,
367         title       => 'Test holiday',
368         description => 'Test holiday'
369     );
370     $charge = $fees->accumulate_rentalcharge();
371     my $day_names = {
372         0 => 'Sunday',
373         1 => 'Monday',
374         2 => 'Tuesday',
375         3 => 'Wednesday',
376         4 => 'Thursday',
377         5 => 'Friday',
378         6 => 'Saturday'
379     };
380     my $dayname = $day_names->{$closed_day};
381     is( $charge, 5.00,
382 "Daily rental charge calculated correctly with finesCalendar = noFinesWhenClosed and closed $dayname"
383     );
384
385     # Hourly tests
386     Koha::CirculationRules->set_rules({
387             categorycode => $patron->categorycode,
388             itemtype     => $itemtype->id,
389             branchcode   => $library->id,
390             rules => {
391                 lengthunit => 'hours',
392             }
393         }
394
395     );
396
397     $itemtype->rentalcharge_hourly("0.25");
398     $itemtype->store();
399
400     $dt_to   = $dt_from->clone->add( hours => 96 );
401     $fees    = Koha::Charges::Fees->new(
402         {
403             patron    => $patron,
404             library   => $library,
405             item      => $item,
406             to_date   => $dt_to,
407             from_date => $dt_from,
408         }
409     );
410
411     t::lib::Mocks::mock_preference( 'finesCalendar', 'ignoreCalendar' );
412     $charge = $fees->accumulate_rentalcharge();
413     is( $charge, 24.00, 'Hourly rental charge calculated correctly (96h * 0.25u)' );
414
415     t::lib::Mocks::mock_preference( 'finesCalendar', 'noFinesWhenClosed' );
416     $charge = $fees->accumulate_rentalcharge();
417     is( $charge, 18.00,
418 "Hourly rental charge calculated correctly with finesCalendar = noFinesWhenClosed and closed $dayname (96h - 24h * 0.25u)"
419     );
420
421     $itemtype->rentalcharge_hourly_calendar(0)->store();
422     $charge = $fees->accumulate_rentalcharge();
423     is( $charge, 24.00,
424 "Hourly rental charge calculated correctly with finesCalendar = noFinesWhenClosed and closed $dayname (96h - 24h * 0.25u) and rentalcharge_hourly_calendar = 0"
425     );
426     $itemtype->rentalcharge_hourly_calendar(1)->store();
427
428     $calendar->delete_holiday( weekday => $closed_day );
429     $charge = $fees->accumulate_rentalcharge();
430     is( $charge, 24.00, 'Hourly rental charge calculated correctly with finesCalendar = noFinesWhenClosed (96h - 0h * 0.25u)' );
431 };
432
433 $schema->storage->txn_rollback;
434 Time::Fake->reset;