Bug 20287: Replace occurrences of AddMember with Koha::Patron->new->store->borrowernumber
[koha.git] / t / db_dependent / Members / IssueSlip.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
19 use Modern::Perl;
20
21 use Data::Dumper; # REMOVEME with diag
22 use Test::More tests => 3;
23 use Test::MockModule;
24 use Test::MockTime qw( set_fixed_time );
25 use t::lib::TestBuilder;
26
27 use C4::Biblio;
28 use C4::Items;
29 use C4::Members;
30 use C4::Circulation;
31
32 use Koha::DateUtils qw( dt_from_string output_pref );
33 use Koha::Library;
34 use Koha::Patrons;
35 use DateTime::Duration;
36
37 use MARC::Record;
38
39 my $schema = Koha::Database->schema;
40 $schema->storage->txn_begin;
41 my $dbh = C4::Context->dbh;
42
43 $dbh->do(q|DELETE FROM issues|);
44 $dbh->do(q|DELETE FROM borrowers|);
45 $dbh->do(q|DELETE FROM items|);
46 $dbh->do(q|DELETE FROM biblio|);
47 $dbh->do(q|DELETE FROM categories|);
48 $dbh->do(q|DELETE FROM letter|);
49
50 my $builder = t::lib::TestBuilder->new;
51 set_fixed_time(CORE::time());
52
53 my $branchcode   = $builder->build({ source => 'Branch' })->{ branchcode };
54 my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
55 my $itemtype     = $builder->build({ source => 'Itemtype' })->{ itemtype };
56
57 my %item_infos = (
58     homebranch    => $branchcode,
59     holdingbranch => $branchcode,
60     itype         => $itemtype
61 );
62
63
64 my $slip_content = <<EOS;
65 Checked out:
66 <checkedout>
67 Title: <<biblio.title>>
68 Barcode: <<items.barcode>>
69 Date due: <<issues.date_due>>
70 </checkedout>
71
72 Overdues:
73 <overdue>
74 Title: <<biblio.title>>
75 Barcode: <<items.barcode>>
76 Date due: <<issues.date_due>>
77 </overdue>
78 EOS
79
80 $dbh->do(q|
81     INSERT INTO letter( module, code, branchcode, name, is_html, title, content, message_transport_type) VALUES ('circulation', 'ISSUESLIP', '', 'Issue Slip', 0, 'Issue Slip', ?, 'email')
82 |, {}, $slip_content);
83
84 my $quick_slip_content = <<EOS;
85 Checked out today:
86 <checkedout>
87 Title: <<biblio.title>>
88 Barcode: <<items.barcode>>
89 Date due: <<issues.date_due>>
90 </checkedout>
91 EOS
92
93 $dbh->do(q|
94     INSERT INTO letter( module, code, branchcode, name, is_html, title, content, message_transport_type) VALUES ('circulation', 'ISSUEQSLIP', '', 'Issue Quick Slip', 0, 'Issue Quick Slip', ?, 'email')
95 |, {}, $quick_slip_content);
96
97 my ( $title1, $title2 ) = ( 'My title 1', 'My title 2' );
98 my ( $barcode1, $barcode2 ) = ('BC0101', 'BC0202' );
99 my $record = MARC::Record->new;
100 $record->append_fields(
101     MARC::Field->new(
102         245, '1', '4',
103             a => $title1,
104     ),
105 );
106 my ($biblionumber1) = AddBiblio( $record, '' );
107 my $itemnumber1 =
108   AddItem( { barcode => $barcode1, %item_infos }, $biblionumber1 );
109
110 $record = MARC::Record->new;
111 $record->append_fields(
112     MARC::Field->new(
113         245, '1', '4',
114             a => $title2,
115     ),
116 );
117 my ($biblionumber2) = AddBiblio( $record, '' );
118 my $itemnumber2 =
119   AddItem( { barcode => $barcode2, %item_infos }, $biblionumber2 );
120
121 my $borrowernumber =
122   Koha::Patron->new({ categorycode => $categorycode, branchcode => $branchcode })->store->borrowernumber;
123 my $borrower = Koha::Patrons->find( $borrowernumber )->unblessed;
124
125 my $module = new Test::MockModule('C4::Context');
126 $module->mock( 'userenv', sub { { branch => $branchcode } } );
127
128 my $today = dt_from_string;
129 my $yesterday = dt_from_string->subtract_duration( DateTime::Duration->new( days => 1 ) );
130
131 subtest 'Issue slip' => sub {
132     plan tests => 3;
133
134     subtest 'Empty slip' => sub {
135         plan tests => 1;
136         my $slip = IssueSlip( $branchcode, $borrowernumber );
137         my $empty_slip = <<EOS;
138 Checked out:
139
140
141 Overdues:
142
143 EOS
144         is( $slip->{content}, $empty_slip, 'No checked out or overdues return an empty slip, it should return undef (FIXME)' );
145     };
146
147     subtest 'Daily loans' => sub {
148         plan tests => 2;
149         skip "It's 23:59!", 2 if $today->hour == 23 and $today->minute == 59;
150         # Test 1: No overdue
151         my $today_daily = $today->clone->set( hour => 23, minute => 59 );
152         my $today_daily_as_formatted = output_pref( $today_daily );
153         my $yesterday_daily = $yesterday->clone->set( hour => 23, minute => 59 );
154         my $yesterday_daily_as_formatted = output_pref( $yesterday_daily );
155
156         my ( $date_due, $issue_date, $slip, $expected_slip );
157         $date_due = $today_daily;
158         $issue_date = $today_daily->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
159         AddIssue( $borrower, $barcode1, $date_due, undef, $issue_date );
160         $date_due = $today_daily;
161         $issue_date = $yesterday_daily;
162         AddIssue( $borrower, $barcode2, $date_due, undef, $issue_date );
163
164         # Set timestamps to the same value to avoid a different order
165         Koha::Checkouts->search(
166             { borrowernumber => $borrower->{borrowernumber} }
167         )->update( { timestamp => dt_from_string } );
168
169         $expected_slip = <<EOS;
170 Checked out:
171
172 Title: $title1
173 Barcode: $barcode1
174 Date due: $today_daily_as_formatted
175
176
177 Title: $title2
178 Barcode: $barcode2
179 Date due: $today_daily_as_formatted
180
181
182 Overdues:
183
184 EOS
185         $slip = IssueSlip( $branchcode, $borrowernumber );
186         is( $slip->{content}, $expected_slip , 'IssueSlip should return a slip with 2 checkouts');
187
188         AddReturn( $barcode1, $branchcode );
189         AddReturn( $barcode2, $branchcode );
190
191         # Test 2: 1 Overdue
192         $date_due = $today_daily;
193         $issue_date = $today_daily->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
194         AddIssue( $borrower, $barcode1, $date_due, undef, $issue_date );
195         $date_due = $yesterday_daily;
196         $issue_date = $yesterday_daily;
197         AddIssue( $borrower, $barcode2, $date_due, undef, $issue_date );
198
199         $expected_slip = <<EOS;
200 Checked out:
201
202 Title: $title1
203 Barcode: $barcode1
204 Date due: $today_daily_as_formatted
205
206
207 Overdues:
208
209 Title: $title2
210 Barcode: $barcode2
211 Date due: $yesterday_daily_as_formatted
212
213 EOS
214         $slip = IssueSlip( $branchcode, $borrowernumber );
215         is( $slip->{content}, $expected_slip, 'IssueSlip should return a slip with 1 checkout and 1 overdue');
216
217         AddReturn( $barcode1, $branchcode );
218         AddReturn( $barcode2, $branchcode );
219     };
220
221     subtest 'Hourly loans' => sub {
222         plan tests => 2;
223         skip "It's 23:59!", 2 if $today->hour == 23 and $today->minute == 59;
224         # Test 1: No overdue
225         my ( $date_due_in_time, $date_due_in_time_as_formatted, $date_due_in_late, $date_due_in_late_as_formatted, $issue_date, $slip, $expected_slip );
226         # Assuming today is not hour = 23 and minute = 59
227         $date_due_in_time = $today->clone->set(hour => ($today->hour < 23 ? $today->hour + 1 : 23), minute => 59);
228         $date_due_in_time_as_formatted = output_pref( $date_due_in_time );
229         $issue_date = $date_due_in_time->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
230         AddIssue( $borrower, $barcode1, $date_due_in_time, undef, $issue_date );
231         $issue_date = $yesterday->clone;
232         AddIssue( $borrower, $barcode2, $date_due_in_time, undef, $issue_date );
233
234         # Set timestamps to the same value to avoid a different order
235         Koha::Checkouts->search(
236             { borrowernumber => $borrower->{borrowernumber} }
237         )->update( { timestamp => dt_from_string } );
238
239         $expected_slip = <<EOS;
240 Checked out:
241
242 Title: $title1
243 Barcode: $barcode1
244 Date due: $date_due_in_time_as_formatted
245
246
247 Title: $title2
248 Barcode: $barcode2
249 Date due: $date_due_in_time_as_formatted
250
251
252 Overdues:
253
254 EOS
255         $slip = IssueSlip( $branchcode, $borrowernumber );
256         is( $slip->{content}, $expected_slip, 'IssueSlip should return a slip with 2 checkouts' )
257             or diag(Dumper(Koha::Checkouts->search({borrowernumber => $borrower->{borrowernumber}})->unblessed));
258
259         AddReturn( $barcode1, $branchcode );
260         AddReturn( $barcode2, $branchcode );
261
262         # Test 2: 1 Overdue
263         $date_due_in_time = $today->clone->set(hour => ($today->hour < 23 ? $today->hour + 1 : 23), minute => 59);
264         $date_due_in_time_as_formatted = output_pref( $date_due_in_time );
265         $issue_date = $date_due_in_time->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
266         AddIssue( $borrower, $barcode1, $date_due_in_time, undef, $issue_date );
267         $date_due_in_late = $today->clone->subtract( hours => 1 );
268         $date_due_in_late_as_formatted = output_pref( $date_due_in_late );
269         $issue_date = $yesterday->clone;
270         AddIssue( $borrower, $barcode2, $date_due_in_late, undef, $issue_date );
271
272         $expected_slip = <<EOS;
273 Checked out:
274
275 Title: $title1
276 Barcode: $barcode1
277 Date due: $date_due_in_time_as_formatted
278
279
280 Overdues:
281
282 Title: $title2
283 Barcode: $barcode2
284 Date due: $date_due_in_late_as_formatted
285
286 EOS
287         $slip = IssueSlip( $branchcode, $borrowernumber );
288         is( $slip->{content}, $expected_slip, 'IssueSlip should return a slip with 1 checkout and 1 overdue' );
289
290         AddReturn( $barcode1, $branchcode );
291         AddReturn( $barcode2, $branchcode );
292     };
293
294 };
295
296 subtest 'Quick slip' => sub {
297     plan tests => 3;
298
299     subtest 'Empty slip' => sub {
300         plan tests => 1;
301         my $slip = IssueSlip( $branchcode, $borrowernumber, 'quick slip' );
302         my $empty_slip = <<EOS;
303 Checked out today:
304
305 EOS
306         is( $slip->{content}, $empty_slip, 'No checked out or overdues return an empty slip, it should return undef (FIXME)' );
307     };
308
309     subtest 'Daily loans' => sub {
310         plan tests => 2;
311         skip "It's 23:59!", 2 if $today->hour == 23 and $today->minute == 59;
312         # Test 1: No overdue
313         my $today_daily = $today->clone->set( hour => 23, minute => 59 );
314         my $today_daily_as_formatted = output_pref( $today_daily );
315         my $yesterday_daily = $yesterday->clone->set( hour => 23, minute => 59 );
316         my $yesterday_daily_as_formatted = output_pref( $yesterday_daily );
317
318         my ( $date_due, $issue_date, $slip, $expected_slip );
319         $date_due = $today_daily;
320         $issue_date = $today_daily->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
321         AddIssue( $borrower, $barcode1, $date_due, undef, $issue_date );
322         $date_due = $today_daily;
323         $issue_date = $yesterday_daily;
324         AddIssue( $borrower, $barcode2, $date_due, undef, $issue_date );
325
326         $expected_slip = <<EOS;
327 Checked out today:
328
329 Title: $title1
330 Barcode: $barcode1
331 Date due: $today_daily_as_formatted
332
333 EOS
334         $slip = IssueSlip( $branchcode, $borrowernumber, 'quick slip' );
335         is( $slip->{content}, $expected_slip, 'IssueSlip should return 2 checkouts for today');
336
337         AddReturn( $barcode1, $branchcode );
338         AddReturn( $barcode2, $branchcode );
339
340         # Test 2: 1 Overdue
341         $date_due = $today_daily;
342         $issue_date = $today_daily->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
343         AddIssue( $borrower, $barcode1, $date_due, undef, $issue_date );
344         $date_due = $yesterday_daily;
345         $issue_date = $yesterday_daily;
346         AddIssue( $borrower, $barcode2, $date_due, undef, $issue_date );
347
348         $expected_slip = <<EOS;
349 Checked out today:
350
351 Title: $title1
352 Barcode: $barcode1
353 Date due: $today_daily_as_formatted
354
355 EOS
356         $slip = IssueSlip( $branchcode, $borrowernumber, 'quickslip' );
357         is( $slip->{content}, $expected_slip );
358     };
359
360     subtest 'Hourly loans' => sub {
361         plan tests => 2;
362         # Test 1: No overdue
363         my ( $date_due_in_time, $date_due_in_time_as_formatted, $date_due_in_late, $date_due_in_late_as_formatted, $issue_date, $slip, $expected_slip );
364         # Assuming today is not hour = 23 and minute = 59
365         $date_due_in_time = $today->clone->set(hour => ($today->hour < 23 ? $today->hour + 1 : 23), minute => 59);
366         $date_due_in_time_as_formatted = output_pref( $date_due_in_time );
367         $issue_date = $date_due_in_time->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
368         AddIssue( $borrower, $barcode1, $date_due_in_time, undef, $issue_date );
369         $issue_date = $yesterday->clone;
370         AddIssue( $borrower, $barcode2, $date_due_in_time, undef, $issue_date );
371
372         $expected_slip = <<EOS;
373 Checked out today:
374
375 Title: $title1
376 Barcode: $barcode1
377 Date due: $date_due_in_time_as_formatted
378
379 EOS
380         $slip = IssueSlip( $branchcode, $borrowernumber, 'quickslip' );
381         is( $slip->{content}, $expected_slip );
382
383         AddReturn( $barcode1, $branchcode );
384         AddReturn( $barcode2, $branchcode );
385
386         # Test 2: 1 Overdue
387         $date_due_in_time = $today->clone->set(hour => ($today->hour < 23 ? $today->hour + 1 : 23), minute => 59);
388         $date_due_in_time_as_formatted = output_pref( $date_due_in_time );
389         $issue_date = $date_due_in_time->clone->subtract_duration( DateTime::Duration->new( minutes => 1 ) );
390         AddIssue( $borrower, $barcode1, $date_due_in_time, undef, $issue_date );
391         $date_due_in_late = $today->clone->subtract( hours => 1 );
392         $date_due_in_late_as_formatted = output_pref( $date_due_in_late );
393         $issue_date = $yesterday->clone;
394         AddIssue( $borrower, $barcode2, $date_due_in_late, undef, $issue_date );
395
396         $expected_slip = <<EOS;
397 Checked out today:
398
399 Title: $title1
400 Barcode: $barcode1
401 Date due: $date_due_in_time_as_formatted
402
403 EOS
404         $slip = IssueSlip( $branchcode, $borrowernumber, 'quickslip' );
405         is( $slip->{content}, $expected_slip );
406
407         AddReturn( $barcode1, $branchcode );
408         AddReturn( $barcode2, $branchcode );
409     };
410
411 };
412
413 subtest 'bad calls' => sub {
414     plan tests => 1;
415     my $slip = IssueSlip();
416     is( $slip, undef, 'IssueSlip should return if no valid borrowernumber is passed' );
417 };
418
419 $schema->storage->txn_rollback;
420