Bug 18292: Remove return 1 statements in tests
[koha.git] / t / db_dependent / Letters / TemplateToolkit.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Copyright (C) 2016 ByWater Solutions
6 # Copyright (C) 2017 Koha Development Team
7 #
8 # Koha is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Koha is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20
21 use Modern::Perl;
22 use Test::More tests => 17;
23 use Test::Warn;
24
25 use MARC::Record;
26
27 use t::lib::TestBuilder;
28
29 use C4::Circulation;
30 use C4::Letters;
31 use C4::Members;
32 use C4::Biblio;
33 use Koha::Database;
34 use Koha::DateUtils;
35 use Koha::ArticleRequests;
36 use Koha::Biblio;
37 use Koha::Biblioitem;
38 use Koha::Item;
39 use Koha::Hold;
40 use Koha::NewsItem;
41 use Koha::Serial;
42 use Koha::Subscription;
43 use Koha::Suggestion;
44 use Koha::Checkout;
45 use Koha::Notice::Messages;
46 use Koha::Notice::Templates;
47 use Koha::Patron::Modification;
48
49 my $schema = Koha::Database->schema;
50 $schema->storage->txn_begin();
51
52 my $builder = t::lib::TestBuilder->new();
53
54 my $dbh = C4::Context->dbh;
55 $dbh->{RaiseError} = 1;
56
57 $dbh->do(q|DELETE FROM letter|);
58
59 my $date = dt_from_string;
60
61 my $library = $builder->build( { source => 'Branch' } );
62 my $patron  = $builder->build( { source => 'Borrower' } );
63 my $patron2 = $builder->build( { source => 'Borrower' } );
64
65 my $biblio = Koha::Biblio->new(
66     {
67         title => 'Test Biblio'
68     }
69 )->store();
70
71 my $biblioitem = Koha::Biblioitem->new(
72     {
73         biblionumber => $biblio->id()
74     }
75 )->store();
76
77 my $item = Koha::Item->new(
78     {
79         biblionumber     => $biblio->id(),
80         biblioitemnumber => $biblioitem->id()
81     }
82 )->store();
83
84 my $hold = Koha::Hold->new(
85     {
86         borrowernumber => $patron->{borrowernumber},
87         biblionumber   => $biblio->id()
88     }
89 )->store();
90
91 my $news         = Koha::NewsItem->new()->store();
92 my $serial       = Koha::Serial->new()->store();
93 my $subscription = Koha::Subscription->new()->store();
94 my $suggestion   = Koha::Suggestion->new()->store();
95 my $checkout     = Koha::Checkout->new( { itemnumber => $item->id() } )->store();
96 my $modification = Koha::Patron::Modification->new( { verification_token => "TEST" } )->store();
97
98 my $prepared_letter;
99
100 my $sth =
101   $dbh->prepare(q{INSERT INTO letter (module, code, name, title, content) VALUES ('test',?,'Test','Test',?)});
102
103 $sth->execute( "TEST_PATRON", "[% borrower.id %]" );
104 $prepared_letter = GetPreparedLetter(
105     (
106         module      => 'test',
107         letter_code => 'TEST_PATRON',
108         tables      => {
109             borrowers => $patron->{borrowernumber},
110         },
111     )
112 );
113 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with scalar' );
114
115 $prepared_letter = GetPreparedLetter(
116     (
117         module      => 'test',
118         letter_code => 'TEST_PATRON',
119         tables      => {
120             borrowers => $patron,
121         },
122     )
123 );
124 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with hashref' );
125
126 $prepared_letter = GetPreparedLetter(
127     (
128         module      => 'test',
129         letter_code => 'TEST_PATRON',
130         tables      => {
131             borrowers => [ $patron->{borrowernumber} ],
132         },
133     )
134 );
135 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with arrayref' );
136
137 $sth->execute( "TEST_BIBLIO", "[% biblio.id %]" );
138 $prepared_letter = GetPreparedLetter(
139     (
140         module      => 'test',
141         letter_code => 'TEST_BIBLIO',
142         tables      => {
143             biblio => $biblio->id(),
144         },
145     )
146 );
147 is( $prepared_letter->{content}, $biblio->id, 'Biblio object used correctly' );
148
149 $sth->execute( "TEST_LIBRARY", "[% branch.id %]" );
150 $prepared_letter = GetPreparedLetter(
151     (
152         module      => 'test',
153         letter_code => 'TEST_LIBRARY',
154         tables      => {
155             branches => $library->{branchcode}
156         },
157     )
158 );
159 is( $prepared_letter->{content}, $library->{branchcode}, 'Library object used correctly' );
160
161 $sth->execute( "TEST_ITEM", "[% item.id %]" );
162 $prepared_letter = GetPreparedLetter(
163     (
164         module      => 'test',
165         letter_code => 'TEST_ITEM',
166         tables      => {
167             items => $item->id()
168         },
169     )
170 );
171 is( $prepared_letter->{content}, $item->id(), 'Item object used correctly' );
172
173 $sth->execute( "TEST_NEWS", "[% news.id %]" );
174 $prepared_letter = GetPreparedLetter(
175     (
176         module      => 'test',
177         letter_code => 'TEST_NEWS',
178         tables      => {
179             opac_news => $news->id()
180         },
181     )
182 );
183 is( $prepared_letter->{content}, $news->id(), 'News object used correctly' );
184
185 $sth->execute( "TEST_HOLD", "[% hold.id %]" );
186 $prepared_letter = GetPreparedLetter(
187     (
188         module      => 'test',
189         letter_code => 'TEST_HOLD',
190         tables      => {
191             reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $biblio->id() },
192         },
193     )
194 );
195 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly' );
196
197 eval {
198     $prepared_letter = GetPreparedLetter(
199         (
200             module      => 'test',
201             letter_code => 'TEST_HOLD',
202             tables      => {
203                 reserves => [ $patron->{borrowernumber}, $biblio->id() ],
204             },
205         )
206     )
207 };
208 my $croak = $@;
209 like( $croak, qr{^Multiple foreign keys \(table reserves\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
210
211 # Bug 16942
212 $prepared_letter = GetPreparedLetter(
213     (
214         module      => 'test',
215         letter_code => 'TEST_HOLD',
216         tables      => {
217             'branches'    => $library,
218             'borrowers'   => $patron,
219             'biblio'      => $biblio->id,
220             'biblioitems' => $biblioitem->id,
221             'reserves'    => $hold->unblessed,
222             'items'       => $hold->itemnumber,
223         }
224     )
225 );
226 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly' );
227
228 $sth->execute( "TEST_SERIAL", "[% serial.id %]" );
229 $prepared_letter = GetPreparedLetter(
230     (
231         module      => 'test',
232         letter_code => 'TEST_SERIAL',
233         tables      => {
234             serial => $serial->id()
235         },
236     )
237 );
238 is( $prepared_letter->{content}, $serial->id(), 'Serial object used correctly' );
239
240 $sth->execute( "TEST_SUBSCRIPTION", "[% subscription.id %]" );
241 $prepared_letter = GetPreparedLetter(
242     (
243         module      => 'test',
244         letter_code => 'TEST_SUBSCRIPTION',
245         tables      => {
246             subscription => $subscription->id()
247         },
248     )
249 );
250 is( $prepared_letter->{content}, $subscription->id(), 'Subscription object used correctly' );
251
252 $sth->execute( "TEST_SUGGESTION", "[% suggestion.id %]" );
253 $prepared_letter = GetPreparedLetter(
254     (
255         module      => 'test',
256         letter_code => 'TEST_SUGGESTION',
257         tables      => {
258             suggestions => $suggestion->id()
259         },
260     )
261 );
262 is( $prepared_letter->{content}, $suggestion->id(), 'Suggestion object used correctly' );
263
264 $sth->execute( "TEST_ISSUE", "[% checkout.id %]" );
265 $prepared_letter = GetPreparedLetter(
266     (
267         module      => 'test',
268         letter_code => 'TEST_ISSUE',
269         tables      => {
270             issues => $item->id()
271         },
272     )
273 );
274 is( $prepared_letter->{content}, $checkout->id(), 'Checkout object used correctly' );
275
276 $sth->execute( "TEST_MODIFICATION", "[% patron_modification.id %]" );
277 $prepared_letter = GetPreparedLetter(
278     (
279         module      => 'test',
280         letter_code => 'TEST_MODIFICATION',
281         tables      => {
282             borrower_modifications => $modification->verification_token,
283         },
284     )
285 );
286 is( $prepared_letter->{content}, $modification->id(), 'Patron modification object used correctly' );
287
288 subtest 'regression tests' => sub {
289     plan tests => 5;
290
291     my $library = $builder->build( { source => 'Branch' } );
292     my $patron  = $builder->build( { source => 'Borrower' } );
293     my $biblio1 = Koha::Biblio->new({title => 'Test Biblio 1', author => 'An author', })->store->unblessed;
294     my $biblioitem1 = Koha::Biblioitem->new({biblionumber => $biblio1->{biblionumber}})->store()->unblessed;
295     my $item1 = Koha::Item->new(
296         {
297             biblionumber     => $biblio1->{biblionumber},
298             biblioitemnumber => $biblioitem1->{biblioitemnumber},
299             barcode          => 'a_t_barcode',
300             homebranch       => $library->{branchcode},
301             holdingbranch    => $library->{branchcode},
302             itype            => 'BK',
303             itemcallnumber   => 'itemcallnumber1',
304         }
305     )->store->unblessed;
306     my $biblio2 = Koha::Biblio->new({title => 'Test Biblio 2'})->store->unblessed;
307     my $biblioitem2 = Koha::Biblioitem->new({biblionumber => $biblio2->{biblionumber}})->store()->unblessed;
308     my $item2 = Koha::Item->new(
309         {
310             biblionumber     => $biblio2->{biblionumber},
311             biblioitemnumber => $biblioitem2->{biblioitemnumber},
312             barcode          => 'another_t_barcode',
313             homebranch       => $library->{branchcode},
314             holdingbranch    => $library->{branchcode},
315             itype            => 'BK',
316             itemcallnumber   => 'itemcallnumber2',
317         }
318     )->store->unblessed;
319
320     C4::Context->_new_userenv('xxx');
321     C4::Context->set_userenv(0,0,0,'firstname','surname', $library->{branchcode}, 'Midway Public Library', '', '', '');
322
323     subtest 'ACQ_NOTIF_ON_RECEIV ' => sub {
324         plan tests => 1;
325         my $code = 'ACQ_NOTIF_ON_RECEIV';
326         my $branchcode = $library->{branchcode};
327         my $order = $builder->build({ source => 'Aqorder' });
328
329         my $template = q|
330 Dear <<borrowers.firstname>> <<borrowers.surname>>,
331 The order <<aqorders.ordernumber>> (<<biblio.title>>) has been received.
332 Your library.
333         |;
334         my $params = { code => $code, branchcode => $branchcode, tables => { branches => $library, borrowers => $patron, biblio => $biblio1, aqorders => $order } };
335         my $letter = process_letter( { template => $template, %$params });
336         my $tt_template = q|
337 Dear [% borrower.firstname %] [% borrower.surname %],
338 The order [% order.ordernumber %] ([% biblio.title %]) has been received.
339 Your library.
340         |;
341         my $tt_letter = process_letter( { template => $tt_template, %$params });
342
343         is( $tt_letter->{content}, $letter->{content}, 'Verified letter content' );
344     };
345
346     subtest 'AR_*' => sub {
347         plan tests => 2;
348         my $code = 'AR_CANCELED';
349         my $branchcode = $library->{branchcode};
350
351         my $template = q|
352 <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)
353
354 Your request for an article from <<biblio.title>> (<<items.barcode>>) has been canceled for the following reason:
355
356 <<article_requests.notes>>
357
358 Article requested:
359 Title: <<article_requests.title>>
360 Author: <<article_requests.author>>
361 Volume: <<article_requests.volume>>
362 Issue: <<article_requests.issue>>
363 Date: <<article_requests.date>>
364 Pages: <<article_requests.pages>>
365 Chapters: <<article_requests.chapters>>
366 Notes: <<article_requests.patron_notes>>
367         |;
368         reset_template( { template => $template, code => $code, module => 'circulation' } );
369         my $article_request = $builder->build({ source => 'ArticleRequest' });
370         Koha::ArticleRequests->find( $article_request->{id} )->cancel;
371         my $letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
372
373         my $tt_template = q|
374 [% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])
375
376 Your request for an article from [% biblio.title %] ([% item.barcode %]) has been canceled for the following reason:
377
378 [% article_request.notes %]
379
380 Article requested:
381 Title: [% article_request.title %]
382 Author: [% article_request.author %]
383 Volume: [% article_request.volume %]
384 Issue: [% article_request.issue %]
385 Date: [% article_request.date %]
386 Pages: [% article_request.pages %]
387 Chapters: [% article_request.chapters %]
388 Notes: [% article_request.patron_notes %]
389         |;
390         reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
391         Koha::ArticleRequests->find( $article_request->{id} )->cancel;
392         my $tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
393         is( $tt_letter->content, $letter->content, 'Compare AR_* notices' );
394         isnt( $tt_letter->message_id, $letter->message_id, 'Comparing AR_* notices should compare 2 different messages' );
395     };
396
397     subtest 'CHECKOUT+CHECKIN' => sub {
398         plan tests => 4;
399
400         my $checkout_code = 'CHECKOUT';
401         my $checkin_code = 'CHECKIN';
402
403         my $dbh = C4::Context->dbh;
404         # Enable notification for CHECKOUT - Things are hardcoded here but should work with default data
405         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 6 );
406         my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
407         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
408         # Enable notification for CHECKIN - Things are hardcoded here but should work with default data
409         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 5 );
410         $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
411         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
412
413         # historic syntax
414         my $checkout_template = q|
415 The following items have been checked out:
416 ----
417 <<biblio.title>>
418 ----
419 Thank you for visiting <<branches.branchname>>.
420 |;
421         reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
422         my $checkin_template = q[
423 The following items have been checked out:
424 ----
425 <<biblio.title>> was due on <<old_issues.date_due | dateonly>>
426 ----
427 Thank you for visiting <<branches.branchname>>.
428 ];
429         reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
430
431         C4::Circulation::AddIssue( $patron, $item1->{barcode} );
432         my $first_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
433         C4::Circulation::AddIssue( $patron, $item2->{barcode} );
434         my $second_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
435
436         AddReturn( $item1->{barcode} );
437         my $first_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
438         AddReturn( $item2->{barcode} );
439         my $second_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
440
441         Koha::Notice::Messages->delete;
442
443         # TT syntax
444         $checkout_template = q|
445 The following items have been checked out:
446 ----
447 [% biblio.title %]
448 ----
449 Thank you for visiting [% branch.branchname %].
450 |;
451         reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
452         $checkin_template = q[
453 The following items have been checked out:
454 ----
455 [% biblio.title %] was due on [% old_checkout.date_due | $KohaDates %]
456 ----
457 Thank you for visiting [% branch.branchname %].
458 ];
459         reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
460
461         C4::Circulation::AddIssue( $patron, $item1->{barcode} );
462         my $first_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
463         C4::Circulation::AddIssue( $patron, $item2->{barcode} );
464         my $second_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
465
466         AddReturn( $item1->{barcode} );
467         my $first_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
468         AddReturn( $item2->{barcode} );
469         my $second_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
470
471         is( $first_checkout_tt_letter->content, $first_checkout_letter->content, 'Verify first checkout letter' );
472         is( $second_checkout_tt_letter->content, $second_checkout_letter->content, 'Verify second checkout letter' );
473         is( $first_checkin_tt_letter->content, $first_checkin_letter->content, 'Verify first checkin letter'  );
474         is( $second_checkin_tt_letter->content, $second_checkin_letter->content, 'Verify second checkin letter' );
475
476     };
477
478     subtest 'DUEDGST|count' => sub {
479         plan tests => 1;
480
481         my $code = 'DUEDGST';
482
483         my $dbh = C4::Context->dbh;
484         # Enable notification for DUEDGST - Things are hardcoded here but should work with default data
485         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 1 );
486         my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
487         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
488
489         my $params = {
490             code => $code,
491             substitute => { count => 42 },
492         };
493
494         my $template = q|
495 You have <<count>> items due
496         |;
497         my $letter = process_letter( { template => $template, %$params });
498
499         my $tt_template = q|
500 You have [% count %] items due
501         |;
502         my $tt_letter = process_letter( { template => $tt_template, %$params });
503         is( $tt_letter->{content}, $letter->{content}, );
504     };
505
506     subtest 'HOLD_SLIP|dates|today' => sub {
507         plan tests => 2;
508
509         my $code = 'HOLD_SLIP';
510
511         C4::Reserves::AddReserve( $library->{branchcode}, $patron->{borrowernumber}, $biblio1->{biblionumber}, undef, undef, undef, undef, "a note", undef, $item1->{itemnumber}, 'W' );
512         C4::Reserves::AddReserve( $library->{branchcode}, $patron->{borrowernumber}, $biblio2->{biblionumber}, undef, undef, undef, undef, "another note", undef, $item2->{itemnumber} );
513
514         my $template = <<EOF;
515 <h5>Date: <<today>></h5>
516
517 <h3> Transfer to/Hold in <<branches.branchname>></h3>
518
519 <h3><<borrowers.surname>>, <<borrowers.firstname>></h3>
520
521 <ul>
522     <li><<borrowers.cardnumber>></li>
523     <li><<borrowers.phone>></li>
524     <li> <<borrowers.address>><br />
525          <<borrowers.address2>><br />
526          <<borrowers.city>>  <<borrowers.zipcode>>
527     </li>
528     <li><<borrowers.email>></li>
529 </ul>
530 <br />
531 <h3>ITEM ON HOLD</h3>
532 <h4><<biblio.title>></h4>
533 <h5><<biblio.author>></h5>
534 <ul>
535    <li><<items.barcode>></li>
536    <li><<items.itemcallnumber>></li>
537    <li><<reserves.waitingdate>></li>
538 </ul>
539 <p>Notes:
540 <pre><<reserves.reservenotes>></pre>
541 </p>
542 EOF
543
544         reset_template( { template => $template, code => $code, module => 'circulation' } );
545         my $letter_for_item1 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio1->{biblionumber} );
546         my $letter_for_item2 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio2->{biblionumber} );
547
548         my $tt_template = <<EOF;
549 <h5>Date: [% today | \$KohaDates with_hours => 1 %]</h5>
550
551 <h3> Transfer to/Hold in [% branch.branchname %]</h3>
552
553 <h3>[% borrower.surname %], [% borrower.firstname %]</h3>
554
555 <ul>
556     <li>[% borrower.cardnumber %]</li>
557     <li>[% borrower.phone %]</li>
558     <li> [% borrower.address %]<br />
559          [% borrower.address2 %]<br />
560          [% borrower.city %]  [% borrower.zipcode %]
561     </li>
562     <li>[% borrower.email %]</li>
563 </ul>
564 <br />
565 <h3>ITEM ON HOLD</h3>
566 <h4>[% biblio.title %]</h4>
567 <h5>[% biblio.author %]</h5>
568 <ul>
569    <li>[% item.barcode %]</li>
570    <li>[% item.itemcallnumber %]</li>
571    <li>[% hold.waitingdate | \$KohaDates %]</li>
572 </ul>
573 <p>Notes:
574 <pre>[% hold.reservenotes %]</pre>
575 </p>
576 EOF
577
578         reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
579         my $tt_letter_for_item1 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio1->{biblionumber} );
580         my $tt_letter_for_item2 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio2->{biblionumber} );
581
582         is( $tt_letter_for_item1->{content}, $letter_for_item1->{content}, );
583         is( $tt_letter_for_item2->{content}, $letter_for_item2->{content}, );
584     };
585 };
586
587 subtest 'loops' => sub {
588     plan tests => 2;
589     my $code = "TEST";
590     my $module = "TEST";
591
592     subtest 'primary key is AI' => sub {
593         plan tests => 1;
594         my $patron_1 = $builder->build({ source => 'Borrower' });
595         my $patron_2 = $builder->build({ source => 'Borrower' });
596
597         my $template = q|[% FOREACH patron IN borrowers %][% patron.surname %][% END %]|;
598         reset_template( { template => $template, code => $code, module => $module } );
599         my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { borrowers => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber} ] } );
600         my $expected_letter = join '', ( $patron_1->{surname}, $patron_2->{surname} );
601         is( $letter->{content}, $expected_letter, );
602     };
603
604     subtest 'foreign key is used' => sub {
605         plan tests => 1;
606         my $patron_1 = $builder->build({ source => 'Borrower' });
607         my $patron_2 = $builder->build({ source => 'Borrower' });
608         my $checkout_1 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
609         my $checkout_2 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
610
611         my $template = q|[% FOREACH checkout IN checkouts %][% checkout.issue_id %][% END %]|;
612         reset_template( { template => $template, code => $code, module => $module } );
613         my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { issues => [ $checkout_1->{itemnumber}, $checkout_2->{itemnumber} ] } );
614         my $expected_letter = join '', ( $checkout_1->{issue_id}, $checkout_2->{issue_id} );
615         is( $letter->{content}, $expected_letter, );
616     };
617 };
618
619 sub reset_template {
620     my ( $params ) = @_;
621     my $template   = $params->{template};
622     my $code       = $params->{code};
623     my $module     = $params->{module} || 'test_module';
624
625     Koha::Notice::Templates->search( { code => $code } )->delete;
626     Koha::Notice::Template->new(
627         {
628             module                 => $module,
629             code                   => $code,
630             branchcode             => '',
631             name                   => $code,
632             title                  => $code,
633             message_transport_type => 'email',
634             content                => $template
635         }
636     )->store;
637 }
638
639 sub process_letter {
640     my ($params)   = @_;
641     my $template   = $params->{template};
642     my $tables     = $params->{tables};
643     my $substitute = $params->{substitute};
644     my $code       = $params->{code};
645     my $module     = $params->{module} || 'test_module';
646     my $branchcode = $params->{branchcode};
647
648     reset_template( $params );
649
650     my $letter = C4::Letters::GetPreparedLetter(
651         module      => $module,
652         letter_code => $code,
653         branchcode  => '',
654         tables      => $tables,
655         substitute  => $substitute,
656     );
657     return $letter;
658 }