Bug 33852: Add one more test
[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) 2022 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 => 31;
23 use Test::MockModule;
24 use Test::Warn;
25
26 use MARC::Record;
27
28 use t::lib::TestBuilder;
29 use t::lib::Mocks;
30
31 use C4::Circulation qw( AddIssue AddReturn );
32 use C4::Letters qw( GetPreparedLetter );
33 use C4::Members qw( IssueSlip );
34 use C4::Biblio;
35 use Koha::Database;
36 use Koha::DateUtils qw( dt_from_string output_pref );
37 use Koha::ArticleRequests;
38 use Koha::Biblio;
39 use Koha::Biblioitem;
40 use Koha::Item;
41 use Koha::Hold;
42 use Koha::AdditionalContents;
43 use Koha::Serial;
44 use Koha::Subscription;
45 use Koha::Suggestion;
46 use Koha::Checkout;
47 use Koha::Patrons;
48 use Koha::Notice::Messages;
49 use Koha::Notice::Templates;
50 use Koha::Patron::Modification;
51
52 my $schema = Koha::Database->schema;
53 $schema->storage->txn_begin();
54
55 my $builder = t::lib::TestBuilder->new();
56
57 my $dbh = C4::Context->dbh;
58
59 $dbh->do(q|DELETE FROM letter|);
60
61 my $now_value       = dt_from_string();
62 my $mocked_datetime = Test::MockModule->new('DateTime');
63 $mocked_datetime->mock( 'now', sub { return $now_value->clone; } );
64
65 my $library = $builder->build( { source => 'Branch' } );
66 my $patron  = $builder->build( { source => 'Borrower' } );
67 my $patron2 = $builder->build( { source => 'Borrower' } );
68
69 my $item = $builder->build_sample_item();
70 my $hold = $builder->build_object(
71     {
72         class => 'Koha::Holds',
73         value => {
74             borrowernumber => $patron->{borrowernumber},
75             biblionumber   => $item->biblionumber
76         }
77     }
78 );
79
80 my $news = $builder->build_object(
81     {
82         class => 'Koha::AdditionalContents',
83         value => { title => 'a news title', content => 'a news content' }
84     }
85 );
86 my $serial       = $builder->build_object( { class => 'Koha::Serials' } );
87 my $subscription = $builder->build_object( { class => 'Koha::Subscriptions' } );
88 my $suggestion   = $builder->build_object( { class => 'Koha::Suggestions' } );
89 my $checkout     = $builder->build_object(
90     { class => 'Koha::Checkouts', value => { itemnumber => $item->id } } );
91 my $modification = $builder->build_object(
92     {
93         class => 'Koha::Patron::Modifications',
94         value => {
95             verification_token => "TEST",
96             changed_fields     => 'firstname,surname'
97         }
98     }
99 );
100
101 my $prepared_letter;
102
103 my $sth =
104   $dbh->prepare(q{INSERT INTO letter (module, code, name, title, content) VALUES ('test',?,'Test',?,?)});
105
106 $sth->execute( "TEST_PATRON", "[% borrower.firstname %]", "[% borrower.id %]" );
107 $prepared_letter = GetPreparedLetter(
108     (
109         module      => 'test',
110         letter_code => 'TEST_PATRON',
111         tables      => {
112             borrowers => $patron->{borrowernumber},
113         },
114     )
115 );
116 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with scalar for content' );
117 is( $prepared_letter->{title}, $patron->{firstname}, 'Patron object used correctly with scalar for title' );
118
119 $prepared_letter = GetPreparedLetter(
120     (
121         module      => 'test',
122         letter_code => 'TEST_PATRON',
123         tables      => {
124             borrowers => $patron,
125         },
126     )
127 );
128 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with hashref for content' );
129 is( $prepared_letter->{title}, $patron->{firstname}, 'Patron object used correctly with hashref for title' );
130
131 $prepared_letter = GetPreparedLetter(
132     (
133         module      => 'test',
134         letter_code => 'TEST_PATRON',
135         tables      => {
136             borrowers => [ $patron->{borrowernumber} ],
137         },
138     )
139 );
140 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with arrayref for content' );
141 is( $prepared_letter->{title}, $patron->{firstname}, 'Patron object used correctly with arrayref for title' );
142
143 $prepared_letter = GetPreparedLetter(
144     (
145         module      => 'test',
146         letter_code => 'TEST_PATRON',
147         objects      => {
148             borrower => scalar Koha::Patrons->find( $patron->{borrowernumber} ),
149         },
150     )
151 );
152 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly as object' );
153
154 $sth->execute( "TEST_BIBLIO", "[% biblio.title %]", "[% biblio.id %]" );
155 $prepared_letter = GetPreparedLetter(
156     (
157         module      => 'test',
158         letter_code => 'TEST_BIBLIO',
159         tables      => {
160             biblio => $item->biblionumber,
161         },
162     )
163 );
164 is( $prepared_letter->{content}, $item->biblionumber, 'Biblio object used correctly for content' );
165 is( $prepared_letter->{title}, $item->biblio->title, 'Biblio object used correctly for title' );
166
167 $sth->execute( "TEST_LIBRARY", "[% branch.branchcode %]", "[% branch.id %]" );
168 $prepared_letter = GetPreparedLetter(
169     (
170         module      => 'test',
171         letter_code => 'TEST_LIBRARY',
172         tables      => {
173             branches => $library->{branchcode}
174         },
175     )
176 );
177 is( $prepared_letter->{content}, $library->{branchcode}, 'Library object used correctly for content' );
178 is( $prepared_letter->{title}, $library->{branchcode}, 'Library object used correctly for title' );
179
180 $sth->execute( "TEST_ITEM", "[% item.barcode %]", "[% item.id %]" );
181 $prepared_letter = GetPreparedLetter(
182     (
183         module      => 'test',
184         letter_code => 'TEST_ITEM',
185         tables      => {
186             items => $item->id()
187         },
188     )
189 );
190 is( $prepared_letter->{content}, $item->id(), 'Item object used correctly for content' );
191 is( $prepared_letter->{title}, $item->barcode, 'Item object used correctly for title' );
192
193 $sth->execute( "TEST_NEWS", "[% additional_content.id %]", "[% additional_content.id %]" );
194 $prepared_letter = GetPreparedLetter(
195     (
196         module      => 'test',
197         letter_code => 'TEST_NEWS',
198         tables      => {
199             additional_contents => $news->id()
200         },
201     )
202 );
203 is( $prepared_letter->{content}, $news->id(), 'News object used correctly for content' );
204 is( $prepared_letter->{title}, $news->id(), 'News object used correctly for title' );
205
206 $sth->execute( "TEST_HOLD", "[% hold.borrowernumber %]", "[% hold.id %]" );
207 $prepared_letter = GetPreparedLetter(
208     (
209         module      => 'test',
210         letter_code => 'TEST_HOLD',
211         tables      => {
212             reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $item->biblionumber },
213         },
214     )
215 );
216 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly for content' );
217 is( $prepared_letter->{title}, $hold->borrowernumber, 'Hold object used correctly for title' );
218
219 eval {
220     $prepared_letter = GetPreparedLetter(
221         (
222             module      => 'test',
223             letter_code => 'TEST_HOLD',
224             tables      => {
225                 reserves => [ $patron->{borrowernumber}, $item->biblionumber ],
226             },
227         )
228     )
229 };
230 my $croak = $@;
231 like( $croak, qr{^Multiple foreign keys \(table reserves\) should be passed using an hashref.*}, "GetPreparedLetter should not be called with arrayref for multiple FK" );
232
233 # Bug 16942
234 $prepared_letter = GetPreparedLetter(
235     (
236         module      => 'test',
237         letter_code => 'TEST_HOLD',
238         tables      => {
239             'branches'    => $library,
240             'borrowers'   => $patron,
241             'biblio'      => $item->biblionumber,
242             'biblioitems' => $item->biblioitemnumber,
243             'reserves'    => $hold->unblessed,
244             'items'       => $hold->itemnumber,
245         }
246     )
247 );
248 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly' );
249
250 $sth->execute( "TEST_SERIAL", "[% serial.id %]", "[% serial.id %]" );
251 $prepared_letter = GetPreparedLetter(
252     (
253         module      => 'test',
254         letter_code => 'TEST_SERIAL',
255         tables      => {
256             serial => $serial->id()
257         },
258     )
259 );
260 is( $prepared_letter->{content}, $serial->id(), 'Serial object used correctly' );
261
262 $sth->execute( "TEST_SUBSCRIPTION", "[% subscription.id %]", "[% subscription.id %]" );
263 $prepared_letter = GetPreparedLetter(
264     (
265         module      => 'test',
266         letter_code => 'TEST_SUBSCRIPTION',
267         tables      => {
268             subscription => $subscription->id()
269         },
270     )
271 );
272 is( $prepared_letter->{content}, $subscription->id(), 'Subscription object used correctly' );
273
274 $sth->execute( "TEST_SUGGESTION", "[% suggestion.id %]", "[% suggestion.id %]" );
275 $prepared_letter = GetPreparedLetter(
276     (
277         module      => 'test',
278         letter_code => 'TEST_SUGGESTION',
279         tables      => {
280             suggestions => $suggestion->id()
281         },
282     )
283 );
284 is( $prepared_letter->{content}, $suggestion->id(), 'Suggestion object used correctly' );
285
286 $sth->execute( "TEST_ISSUE", "[% checkout.id %]", "[% checkout.id %]" );
287 $prepared_letter = GetPreparedLetter(
288     (
289         module      => 'test',
290         letter_code => 'TEST_ISSUE',
291         tables      => {
292             issues => $item->id()
293         },
294     )
295 );
296 is( $prepared_letter->{content}, $checkout->id(), 'Checkout object used correctly' );
297
298 $sth->execute( "TEST_MODIFICATION", "[% patron_modification.id %]", "[% patron_modification.id %]" );
299 $prepared_letter = GetPreparedLetter(
300     (
301         module      => 'test',
302         letter_code => 'TEST_MODIFICATION',
303         tables      => {
304             borrower_modifications => $modification->verification_token,
305         },
306     )
307 );
308 is( $prepared_letter->{content}, $modification->id(), 'Patron modification object used correctly' );
309
310 subtest 'regression tests' => sub {
311     plan tests => 8;
312
313     my $library = $builder->build( { source => 'Branch' } );
314     my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' })->store->itemtype;
315
316     my $item1 = $builder->build_sample_item(
317         {
318             barcode        => 'a_t_barcode',
319             library        => $library->{branchcode},
320             itype          => $itemtype,
321             itemcallnumber => 'itemcallnumber1',
322         }
323     );
324     my $biblio1 = $item1->biblio->unblessed;
325     $item1 = $item1->unblessed;
326     my $item2   = $builder->build_sample_item(
327         {
328             barcode        => 'another_t_barcode',
329             library        => $library->{branchcode},
330             itype          => $itemtype,
331             itemcallnumber => 'itemcallnumber2',
332         }
333     );
334     my $biblio2 = $item2->biblio->unblessed;
335     $item2 = $item2->unblessed;
336     my $item3   = $builder->build_sample_item(
337         {
338             barcode        => 'another_t_barcode_3',
339             library        => $library->{branchcode},
340             itype          => $itemtype,
341             itemcallnumber => 'itemcallnumber3',
342         }
343     );
344     my $biblio3 = $item3->biblio->unblessed;
345     $item3 = $item3->unblessed;
346
347     t::lib::Mocks::mock_userenv({ branchcode => $library->{branchcode} });
348
349     subtest 'ACQ_NOTIF_ON_RECEIV ' => sub {
350         plan tests => 1;
351         my $code = 'ACQ_NOTIF_ON_RECEIV';
352         my $branchcode = $library->{branchcode};
353         my $order = $builder->build({ source => 'Aqorder' });
354
355         my $template = q|
356 Dear <<borrowers.firstname>> <<borrowers.surname>>,
357 The order <<aqorders.ordernumber>> (<<biblio.title>>) has been received.
358 Your library.
359         |;
360         my $params = { code => $code, branchcode => $branchcode, tables => { branches => $library, borrowers => $patron, biblio => $biblio1, aqorders => $order } };
361         my $letter = process_letter( { template => $template, %$params });
362         my $tt_template = q|
363 Dear [% borrower.firstname %] [% borrower.surname %],
364 The order [% order.ordernumber %] ([% biblio.title %]) has been received.
365 Your library.
366         |;
367         my $tt_letter = process_letter( { template => $tt_template, %$params });
368
369         is( $tt_letter->{content}, $letter->{content}, 'Verified letter content' );
370     };
371
372     subtest 'AR_*' => sub {
373         plan tests => 2;
374         my $code = 'AR_CANCELED';
375         my $branchcode = $library->{branchcode};
376
377         my $template = q|
378 <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)
379
380 Your request for an article from <<biblio.title>> (<<items.barcode>>) has been canceled for the following reason:
381
382 <<article_requests.notes>>
383
384 Article requested:
385 Title: <<article_requests.title>>
386 Author: <<article_requests.author>>
387 Volume: <<article_requests.volume>>
388 Issue: <<article_requests.issue>>
389 Date: <<article_requests.date>>
390 Pages: <<article_requests.pages>>
391 Chapters: <<article_requests.chapters>>
392 Notes: <<article_requests.patron_notes>>
393         |;
394         reset_template( { template => $template, code => $code, module => 'circulation' } );
395         my $article_request = $builder->build_object(
396             {
397                 class => 'Koha::ArticleRequests',
398                 value => { debit_id => undef }
399             }
400         );
401         $article_request->cancel;
402         my $letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
403
404         my $tt_template = q|
405 [% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])
406
407 Your request for an article from [% biblio.title %] ([% item.barcode %]) has been canceled for the following reason:
408
409 [% article_request.notes %]
410
411 Article requested:
412 Title: [% article_request.title %]
413 Author: [% article_request.author %]
414 Volume: [% article_request.volume %]
415 Issue: [% article_request.issue %]
416 Date: [% article_request.date %]
417 Pages: [% article_request.pages %]
418 Chapters: [% article_request.chapters %]
419 Notes: [% article_request.patron_notes %]
420         |;
421         reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
422         $article_request->cancel;
423         my $tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
424         is( $tt_letter->content, $letter->content, 'Compare AR_* notices' );
425         isnt( $tt_letter->message_id, $letter->message_id, 'Comparing AR_* notices should compare 2 different messages' );
426     };
427
428     subtest 'CHECKOUT+CHECKIN' => sub {
429         plan tests => 4;
430
431         my $checkout_code = 'CHECKOUT';
432         my $checkin_code = 'CHECKIN';
433
434         my $dbh = C4::Context->dbh;
435         # Enable notification for CHECKOUT - Things are hardcoded here but should work with default data
436         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 6 );
437         my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
438         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
439         # Enable notification for CHECKIN - Things are hardcoded here but should work with default data
440         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 5 );
441         $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
442         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
443
444         # historic syntax
445         my $checkout_template = q|
446 The following items have been checked out:
447 ----
448 <<biblio.title>>
449 ----
450 Thank you for visiting <<branches.branchname>>.
451 |;
452         reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
453         my $checkin_template = q[
454 The following items have been checked out:
455 ----
456 <<biblio.title>> was due on <<old_issues.date_due | dateonly>>
457 ----
458 Thank you for visiting <<branches.branchname>>.
459 ];
460         reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
461
462         C4::Circulation::AddIssue( $patron, $item1->{barcode} );
463         my $first_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
464         C4::Circulation::AddIssue( $patron, $item2->{barcode} );
465         my $second_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
466
467         AddReturn( $item1->{barcode} );
468         my $first_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
469         AddReturn( $item2->{barcode} );
470         my $second_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
471
472         Koha::Notice::Messages->delete;
473
474         # TT syntax
475         $checkout_template = q|
476 The following items have been checked out:
477 ----
478 [% biblio.title %]
479 ----
480 Thank you for visiting [% branch.branchname %].
481 |;
482         reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
483         $checkin_template = q[
484 The following items have been checked out:
485 ----
486 [% biblio.title %] was due on [% old_checkout.date_due | $KohaDates %]
487 ----
488 Thank you for visiting [% branch.branchname %].
489 ];
490         reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
491
492         C4::Circulation::AddIssue( $patron, $item1->{barcode} );
493         my $first_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
494         C4::Circulation::AddIssue( $patron, $item2->{barcode} );
495         my $second_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
496
497         AddReturn( $item1->{barcode} );
498         my $first_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
499         AddReturn( $item2->{barcode} );
500         my $second_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
501
502         is( $first_checkout_tt_letter->content, $first_checkout_letter->content, 'Verify first checkout letter' );
503         is( $second_checkout_tt_letter->content, $second_checkout_letter->content, 'Verify second checkout letter' );
504         is( $first_checkin_tt_letter->content, $first_checkin_letter->content, 'Verify first checkin letter'  );
505         is( $second_checkin_tt_letter->content, $second_checkin_letter->content, 'Verify second checkin letter' );
506
507     };
508
509     subtest 'DUEDGST|count' => sub {
510         plan tests => 1;
511
512         my $code = 'DUEDGST';
513
514         my $dbh = C4::Context->dbh;
515         # Enable notification for DUEDGST - Things are hardcoded here but should work with default data
516         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 1 );
517         my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
518         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
519
520         my $params = {
521             code => $code,
522             substitute => { count => 42 },
523         };
524
525         my $template = q|
526 You have <<count>> items due
527         |;
528         my $letter = process_letter( { template => $template, %$params });
529
530         my $tt_template = q|
531 You have [% count %] items due
532         |;
533         my $tt_letter = process_letter( { template => $tt_template, %$params });
534         is( $tt_letter->{content}, $letter->{content}, );
535     };
536
537     subtest 'HOLD_SLIP|dates|today' => sub {
538         plan tests => 2;
539
540         my $code = 'HOLD_SLIP';
541
542         my $reserve_id1 = C4::Reserves::AddReserve(
543             {
544                 branchcode     => $library->{branchcode},
545                 borrowernumber => $patron->{borrowernumber},
546                 biblionumber   => $biblio1->{biblionumber},
547                 notes          => "a note",
548                 itemnumber     => $item1->{itemnumber},
549             }
550         );
551         my $reserve_id2 = C4::Reserves::AddReserve(
552             {
553                 branchcode     => $library->{branchcode},
554                 borrowernumber => $patron->{borrowernumber},
555                 biblionumber   => $biblio1->{biblionumber},
556                 notes          => "a note",
557                 itemnumber     => $item1->{itemnumber},
558             }
559         );
560         my $reserve_id3 = C4::Reserves::AddReserve(
561             {
562                 branchcode     => $library->{branchcode},
563                 borrowernumber => $patron->{borrowernumber},
564                 biblionumber   => $biblio2->{biblionumber},
565                 notes          => "another note",
566                 itemnumber     => $item2->{itemnumber},
567             }
568         );
569
570         my $template = <<EOF;
571 <h5>Date: <<today>></h5>
572
573 <h3> Transfer to/Hold in <<branches.branchname>></h3>
574
575 <h3><<borrowers.surname>>, <<borrowers.firstname>></h3>
576
577 <ul>
578     <li><<borrowers.cardnumber>></li>
579     <li><<borrowers.phone>></li>
580     <li> <<borrowers.address>><br />
581          <<borrowers.address2>><br />
582          <<borrowers.city>>  <<borrowers.zipcode>>
583     </li>
584     <li><<borrowers.email>></li>
585 </ul>
586 <br />
587 <h3>ITEM ON HOLD</h3>
588 <h4><<biblio.title>></h4>
589 <h5><<biblio.author>></h5>
590 <ul>
591    <li><<items.barcode>></li>
592    <li><<items.itemcallnumber>></li>
593    <li><<reserves.waitingdate>></li>
594 </ul>
595 <p>Notes:
596 <pre><<reserves.reserve_id>>=<<reserves.reservenotes>></pre>
597 </p>
598 EOF
599
600         reset_template( { template => $template, code => $code, module => 'circulation' } );
601         my $letter_for_item1 = C4::Reserves::ReserveSlip( { branchcode => $library->{branchcode}, reserve_id => $reserve_id1 } );
602         my $letter_for_item2 = C4::Reserves::ReserveSlip( { branchcode => $library->{branchcode}, reserve_id => $reserve_id3 } );
603
604         my $tt_template = <<EOF;
605 <h5>Date: [% today | \$KohaDates with_hours => 1 %]</h5>
606
607 <h3> Transfer to/Hold in [% branch.branchname %]</h3>
608
609 <h3>[% borrower.surname %], [% borrower.firstname %]</h3>
610
611 <ul>
612     <li>[% borrower.cardnumber %]</li>
613     <li>[% borrower.phone %]</li>
614     <li> [% borrower.address %]<br />
615          [% borrower.address2 %]<br />
616          [% borrower.city %]  [% borrower.zipcode %]
617     </li>
618     <li>[% borrower.email %]</li>
619 </ul>
620 <br />
621 <h3>ITEM ON HOLD</h3>
622 <h4>[% biblio.title %]</h4>
623 <h5>[% biblio.author %]</h5>
624 <ul>
625    <li>[% item.barcode %]</li>
626    <li>[% item.itemcallnumber %]</li>
627    <li>[% hold.waitingdate | \$KohaDates %]</li>
628 </ul>
629 <p>Notes:
630 <pre>[% hold.reserve_id %]=[% hold.reservenotes %]</pre>
631 </p>
632 EOF
633
634         reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
635         my $tt_letter_for_item1 = C4::Reserves::ReserveSlip( { branchcode => $library->{branchcode}, reserve_id => $reserve_id1 } );
636         my $tt_letter_for_item2 = C4::Reserves::ReserveSlip( { branchcode => $library->{branchcode}, reserve_id => $reserve_id3 } );
637
638         is( $tt_letter_for_item1->{content}, $letter_for_item1->{content}, );
639         is( $tt_letter_for_item2->{content}, $letter_for_item2->{content}, );
640     };
641
642     subtest 'ISSUESLIP|checkedout|repeat|news' => sub {
643         plan tests => 3;
644
645         my $code = 'ISSUESLIP';
646         my $now = dt_from_string;
647         my $one_minute_ago = dt_from_string->subtract( minutes => 1 );
648
649         my $branchcode = $library->{branchcode};
650
651         Koha::AdditionalContents->delete;
652         my $news_item = $builder->build_object(
653             {
654                 class => 'Koha::AdditionalContents',
655                 value => {
656                     category        => 'news',
657                     location        => "slip",
658                     branchcode      => $branchcode,
659                     lang            => 'default',
660                     title           => "A wonderful news",
661                     content         => "This is the wonderful news.",
662                     expirationdate  => undef,
663                     published_on    => $one_minute_ago
664                 }
665             }
666         );
667
668         # historic syntax
669         my $template = <<EOF;
670 <h3><<branches.branchname>></h3>
671 Checked out to <<borrowers.title>> <<borrowers.firstname>> <<borrowers.initials>> <<borrowers.surname>> <br />
672 (<<borrowers.cardnumber>>) <br />
673
674 <<today>><br />
675
676 <h4>Checked out</h4>
677 <checkedout>
678 <p>
679 <<biblio.title>> <br />
680 Barcode: <<items.barcode>><br />
681 Date due: <<issues.date_due | dateonly>><br />
682 </p>
683 </checkedout>
684
685 <h4>Overdues</h4>
686 <overdue>
687 <p>
688 <<biblio.title>> <br />
689 Barcode: <<items.barcode>><br />
690 Date due: <<issues.date_due | dateonly>><br />
691 </p>
692 </overdue>
693
694 <hr>
695
696 <h4 style="text-align: center; font-style:italic;">News</h4>
697 <news>
698 <div class="newsitem">
699 <h5 style="margin-bottom: 1px; margin-top: 1px"><b><<additional_contents.title>></b></h5>
700 <p style="margin-bottom: 1px; margin-top: 1px"><<additional_contents.content>></p>
701 <p class="newsfooter" style="font-size: 8pt; font-style:italic; margin-bottom: 1px; margin-top: 1px">Posted on <<additional_contents.published_on>></p>
702 <hr />
703 </div>
704 </news>
705 EOF
706
707         reset_template( { template => $template, code => $code, module => 'circulation' } );
708
709         my $checkout = C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
710         $checkout->set( { timestamp => $now, issuedate => $one_minute_ago } )->store;
711         my $first_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
712
713         $checkout = C4::Circulation::AddIssue( $patron, $item2->{barcode} ); # Add a second checkout
714         $checkout->set( { timestamp => $now, issuedate => $now } )->store;
715         my $yesterday = dt_from_string->subtract( days => 1 );
716         C4::Circulation::AddIssue( $patron, $item3->{barcode}, $yesterday ); # Add an overdue
717         my $second_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
718
719         # Cleanup
720         AddReturn( $item1->{barcode} );
721         AddReturn( $item2->{barcode} );
722         AddReturn( $item3->{barcode} );
723
724         # TT syntax
725         my $tt_template = <<EOF;
726 <h3>[% branch.branchname %]</h3>
727 Checked out to [% borrower.title %] [% borrower.firstname %] [% borrower.initials %] [% borrower.surname %] <br />
728 ([% borrower.cardnumber %]) <br />
729
730 [% today | \$KohaDates with_hours => 1 %]<br />
731
732 <h4>Checked out</h4>
733 [% FOREACH checkout IN checkouts %]
734 [%~ SET item = checkout.item %]
735 [%~ SET biblio = checkout.item.biblio %]
736 <p>
737 [% biblio.title %] <br />
738 Barcode: [% item.barcode %]<br />
739 Date due: [% checkout.date_due | \$KohaDates %]<br />
740 </p>
741 [% END %]
742
743 <h4>Overdues</h4>
744 [% FOREACH overdue IN overdues %]
745 [%~ SET item = overdue.item %]
746 [%~ SET biblio = overdue.item.biblio %]
747 <p>
748 [% biblio.title %] <br />
749 Barcode: [% item.barcode %]<br />
750 Date due: [% overdue.date_due | \$KohaDates %]<br />
751 </p>
752 [% END %]
753
754 <hr>
755
756 <h4 style="text-align: center; font-style:italic;">News</h4>
757 [% FOREACH n IN additional_contents %]
758 <div class="newsitem">
759 <h5 style="margin-bottom: 1px; margin-top: 1px"><b>[% n.title %]</b></h5>
760 <p style="margin-bottom: 1px; margin-top: 1px">[% n.content %]</p>
761 <p class="newsfooter" style="font-size: 8pt; font-style:italic; margin-bottom: 1px; margin-top: 1px">Posted on [% n.published_on | \$KohaDates %]</p>
762 <hr />
763 </div>
764 [% END %]
765 EOF
766
767         reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
768
769         $checkout = C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
770         $checkout->set( { timestamp => $now, issuedate => $one_minute_ago } )->store;
771         my $first_tt_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
772
773         $checkout = C4::Circulation::AddIssue( $patron, $item2->{barcode} ); # Add a second checkout
774         $checkout->set( { timestamp => $now, issuedate => $now } )->store;
775         C4::Circulation::AddIssue( $patron, $item3->{barcode}, $yesterday ); # Add an overdue
776         my $second_tt_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
777
778         # There is too many line breaks generated by the historic syntax
779         $second_slip->{content} =~ s|</p>\n\n\n<p>|</p>\n\n<p>|s;
780
781         my $news_item_title = $news_item->title;
782         like( $first_slip->{content}, qr{$news_item_title} );
783         is( $first_tt_slip->{content}, $first_slip->{content}, );
784         is( $second_tt_slip->{content}, $second_slip->{content}, );
785
786         # Cleanup
787         AddReturn( $item1->{barcode} );
788         AddReturn( $item2->{barcode} );
789         AddReturn( $item3->{barcode} );
790     };
791
792     subtest 'ODUE|items.content|item' => sub {
793         plan tests => 1;
794
795         my $code = 'ODUE';
796
797         my $branchcode = $library->{branchcode};
798
799         # historic syntax
800         # FIXME items.fine does not work with TT notices
801         # See bug 17976
802         # <item> should contain Fine: <<items.fine>></item>
803         my $template = <<EOF;
804 Dear <<borrowers.firstname>> <<borrowers.surname>>,
805
806 According to our current records, you have items that are overdue.Your library does not charge late fines, but please return or renew them at the branch below as soon as possible.
807
808 <<branches.branchname>>
809 <<branches.branchaddress1>>
810 <<branches.branchaddress2>> <<branches.branchaddress3>>
811 Phone: <<branches.branchphone>>
812 Fax: <<branches.branchfax>>
813 Email: <<branches.branchemail>>
814
815 If you have registered a password with the library, and you have a renewal available, you may renew online. If an item becomes more than 30 days overdue, you will be unable to use your library card until the item is returned.
816
817 The following item(s) is/are currently overdue:
818
819 <item>"<<biblio.title>>" by <<biblio.author>>, <<items.itemcallnumber>>, Barcode: <<items.barcode>></item>
820
821 <<items.content>>
822
823 Thank-you for your prompt attention to this matter.
824
825 <<branches.branchname>> Staff
826 EOF
827
828         reset_template( { template => $template, code => $code, module => 'circulation' } );
829
830         my $yesterday = dt_from_string->subtract( days => 1 );
831         my $two_days_ago = dt_from_string->subtract( days => 2 );
832         my $issue1 = C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
833         my $issue2 = C4::Circulation::AddIssue( $patron, $item2->{barcode}, $yesterday ); # Add an first overdue
834         my $issue3 = C4::Circulation::AddIssue( $patron, $item3->{barcode}, $two_days_ago ); # Add an second overdue
835         $issue1 = $issue1->unblessed;
836         $issue2 = $issue2->unblessed;
837         $issue3 = $issue3->unblessed;
838
839         # For items.content
840         my @item_fields = qw( date_due title barcode author itemnumber );
841         my $items_content = C4::Letters::get_item_content( { item => { %$item1, %$biblio1, %$issue1 }, item_content_fields => \@item_fields, dateonly => 1 } );
842           $items_content .= C4::Letters::get_item_content( { item => { %$item2, %$biblio2, %$issue2 }, item_content_fields => \@item_fields, dateonly => 1 } );
843           $items_content .= C4::Letters::get_item_content( { item => { %$item3, %$biblio3, %$issue3 }, item_content_fields => \@item_fields, dateonly => 1 } );
844
845         my @items = ( $item1, $item2, $item3 );
846         my $letter = C4::Overdues::parse_overdues_letter(
847             {
848                 letter_code => $code,
849                 borrowernumber => $patron->{borrowernumber},
850                 branchcode  => $library->{branchcode},
851                 items       => \@items,
852                 substitute  => {
853                     bib                    => $library->{branchname},
854                     'items.content'        => $items_content,
855                     count                  => scalar( @items ),
856                     message_transport_type => 'email',
857                 }
858             }
859         );
860
861         # Cleanup
862         AddReturn( $item1->{barcode} );
863         AddReturn( $item2->{barcode} );
864         AddReturn( $item3->{barcode} );
865
866
867         # historic syntax
868         my $tt_template = <<EOF;
869 Dear [% borrower.firstname %] [% borrower.surname %],
870
871 According to our current records, you have items that are overdue.Your library does not charge late fines, but please return or renew them at the branch below as soon as possible.
872
873 [% branch.branchname %]
874 [% branch.branchaddress1 %]
875 [% branch.branchaddress2 %] [% branch.branchaddress3 %]
876 Phone: [% branch.branchphone %]
877 Fax: [% branch.branchfax %]
878 Email: [% branch.branchemail %]
879
880 If you have registered a password with the library, and you have a renewal available, you may renew online. If an item becomes more than 30 days overdue, you will be unable to use your library card until the item is returned.
881
882 The following item(s) is/are currently overdue:
883
884 [% FOREACH overdue IN overdues %]
885 [%~ SET item = overdue.item ~%]
886 "[% item.biblio.title %]" by [% item.biblio.author %], [% item.itemcallnumber %], Barcode: [% item.barcode %]
887 [% END %]
888 [% FOREACH overdue IN overdues %]
889 [%~ SET item = overdue.item ~%]
890 [% overdue.date_due | \$KohaDates %]\t[% item.biblio.title %]\t[% item.barcode %]\t[% item.biblio.author %]\t[% item.itemnumber %]
891 [% END %]
892
893 Thank-you for your prompt attention to this matter.
894
895 [% branch.branchname %] Staff
896 EOF
897
898         reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
899
900         C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
901         C4::Circulation::AddIssue( $patron, $item2->{barcode}, $yesterday ); # Add an first overdue
902         C4::Circulation::AddIssue( $patron, $item3->{barcode}, $two_days_ago ); # Add an second overdue
903
904         my $tt_letter = C4::Overdues::parse_overdues_letter(
905             {
906                 letter_code => $code,
907                 borrowernumber => $patron->{borrowernumber},
908                 branchcode  => $library->{branchcode},
909                 items       => \@items,
910                 substitute  => {
911                     bib                    => $library->{branchname},
912                     'items.content'        => $items_content,
913                     count                  => scalar( @items ),
914                     message_transport_type => 'email',
915                 }
916             }
917         );
918
919         is( $tt_letter->{content}, $letter->{content}, );
920     };
921
922     subtest 'Bug 19743 - Header and Footer should be updated on each item for checkin / checkout / renewal notices' => sub {
923         plan tests => 8;
924
925         my $checkout_code = 'CHECKOUT';
926         my $checkin_code = 'CHECKIN';
927
928         my $dbh = C4::Context->dbh;
929         $dbh->do("DELETE FROM letter");
930         $dbh->do("DELETE FROM issues");
931         $dbh->do("DELETE FROM message_queue");
932
933         # Enable notification for CHECKOUT - Things are hardcoded here but should work with default data
934         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 6 );
935         my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
936         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
937         # Enable notification for CHECKIN - Things are hardcoded here but should work with default data
938         $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 5 );
939         $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
940         $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
941
942         my $checkout_template = q|
943 <<branches.branchname>>
944 ----
945 ----
946 |;
947         reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
948         my $checkin_template = q[
949 <<branches.branchname>>
950 ----
951 ----
952 ];
953         reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
954
955         my $issue = C4::Circulation::AddIssue( $patron, $item1->{barcode} );
956         my $first_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
957
958         my $library_object = Koha::Libraries->find( $issue->branchcode );
959         my $old_branchname = $library_object->branchname;
960         my $new_branchname = "Kyle M Hall Memorial Library";
961
962         # Change branch name for second checkout notice
963         $library_object->branchname($new_branchname);
964         $library_object->store();
965
966         C4::Circulation::AddIssue( $patron, $item2->{barcode} );
967         my $second_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
968
969         # Restore old name for first checkin notice
970         $library_object->branchname( $old_branchname );
971         $library_object->store();
972
973         AddReturn( $item1->{barcode} );
974         my $first_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
975
976         # Change branch name for second checkin notice
977         $library_object->branchname($new_branchname);
978         $library_object->store();
979
980         AddReturn( $item2->{barcode} );
981         my $second_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
982
983         # Restore old name for first TT checkout notice
984         $library_object->branchname( $old_branchname );
985         $library_object->store();
986
987         Koha::Notice::Messages->delete;
988
989         # TT syntax
990         $checkout_template = q|
991 [% branch.branchname %]
992 ----
993 ----
994 |;
995         reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
996         $checkin_template = q[
997 [% branch.branchname %]
998 ----
999 ----
1000 ];
1001         reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
1002
1003         C4::Circulation::AddIssue( $patron, $item1->{barcode} );
1004         my $first_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
1005
1006         # Change branch name for second checkout notice
1007         $library_object->branchname($new_branchname);
1008         $library_object->store();
1009
1010         C4::Circulation::AddIssue( $patron, $item2->{barcode} );
1011         my $second_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
1012
1013         # Restore old name for first checkin notice
1014         $library_object->branchname( $old_branchname );
1015         $library_object->store();
1016
1017         AddReturn( $item1->{barcode} );
1018         my $first_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
1019 #
1020         # Change branch name for second checkin notice
1021         $library_object->branchname($new_branchname);
1022         $library_object->store();
1023
1024         AddReturn( $item2->{barcode} );
1025         my $second_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
1026
1027         my $first_letter = qq[
1028 $old_branchname
1029 ];
1030         my $second_letter = qq[
1031 $new_branchname
1032 ];
1033
1034
1035         is( $first_checkout_letter->content, $first_letter, 'Verify first checkout letter' );
1036         is( $second_checkout_letter->content, $second_letter, 'Verify second checkout letter' );
1037         is( $first_checkin_letter->content, $first_letter, 'Verify first checkin letter'  );
1038         is( $second_checkin_letter->content, $second_letter, 'Verify second checkin letter' );
1039
1040         is( $first_checkout_tt_letter->content, $first_letter, 'Verify TT first checkout letter' );
1041         is( $second_checkout_tt_letter->content, $second_letter, 'Verify TT second checkout letter' );
1042         is( $first_checkin_tt_letter->content, $first_letter, 'Verify TT first checkin letter'  );
1043         is( $second_checkin_tt_letter->content, $second_letter, 'Verify TT second checkin letter' );
1044     };
1045
1046 };
1047
1048 subtest 'loops' => sub {
1049     plan tests => 2;
1050     my $code = "TEST";
1051     my $module = "TEST";
1052
1053     subtest 'primary key is AI' => sub {
1054         plan tests => 1;
1055         my $patron_1 = $builder->build({ source => 'Borrower' });
1056         my $patron_2 = $builder->build({ source => 'Borrower' });
1057
1058         my $template = q|[% FOREACH patron IN borrowers %][% patron.surname %][% END %]|;
1059         reset_template( { template => $template, code => $code, module => $module } );
1060         my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { borrowers => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber} ] } );
1061         my $expected_letter = join '', ( $patron_1->{surname}, $patron_2->{surname} );
1062         is( $letter->{content}, $expected_letter, );
1063     };
1064
1065     subtest 'foreign key is used' => sub {
1066         plan tests => 1;
1067         my $patron_1 = $builder->build({ source => 'Borrower' });
1068         my $patron_2 = $builder->build({ source => 'Borrower' });
1069         my $checkout_1 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
1070         my $checkout_2 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
1071
1072         my $template = q|[% FOREACH checkout IN checkouts %][% checkout.issue_id %][% END %]|;
1073         reset_template( { template => $template, code => $code, module => $module } );
1074         my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { issues => [ $checkout_1->{itemnumber}, $checkout_2->{itemnumber} ] } );
1075         my $expected_letter = join '', ( $checkout_1->{issue_id}, $checkout_2->{issue_id} );
1076         is( $letter->{content}, $expected_letter, );
1077     };
1078 };
1079
1080 subtest 'add_tt_filters' => sub {
1081     plan tests => 1;
1082     my $code   = "TEST";
1083     my $module = "TEST";
1084
1085     my $patron = $builder->build_object(
1086         {
1087             class => 'Koha::Patrons',
1088             value => { surname => "with_punctuation_" }
1089         }
1090     );
1091     my $biblio = $builder->build_object(
1092         { class => 'Koha::Biblios', value => { title => "with_punctuation_" } }
1093     );
1094     my $biblioitem = $builder->build_object(
1095         {
1096             class => 'Koha::Biblioitems',
1097             value => {
1098                 biblionumber => $biblio->biblionumber,
1099                 isbn         => "with_punctuation_"
1100             }
1101         }
1102     );
1103
1104     my $template = q|patron=[% borrower.surname %];biblio=[% biblio.title %];biblioitems=[% biblioitem.isbn %]|;
1105     reset_template( { template => $template, code => $code, module => $module } );
1106     my $letter = GetPreparedLetter(
1107         module      => $module,
1108         letter_code => $code,
1109         tables      => {
1110             borrowers   => $patron->borrowernumber,
1111             biblio      => $biblio->biblionumber,
1112             biblioitems => $biblioitem->biblioitemnumber
1113         }
1114     );
1115     my $expected_letter = q|patron=with_punctuation_;biblio=with_punctuation;biblioitems=with_punctuation|;
1116     is( $letter->{content}, $expected_letter, "Pre-processing should call TT plugin to remove punctuation if table is biblio or biblioitems");
1117 };
1118
1119 subtest 'Handle includes' => sub {
1120     plan tests => 1;
1121     my $cgi = CGI->new();
1122     my $code = 'TEST_INCLUDE';
1123     my $account =
1124       $builder->build_object( { class => 'Koha::Account::Lines', value => { credit_type_code => 'PAYMENT', status => 'CANCELLED' } } );
1125     my $template = <<EOF;
1126 [%- USE Price -%]
1127 [%- PROCESS 'accounts.inc' -%]
1128 [%- PROCESS account_type_description account=credit -%]
1129 EOF
1130     reset_template({ template => $template, code => $code, module => 'test' });
1131     my $letter = GetPreparedLetter(
1132         module      => 'test',
1133         letter_code => $code,
1134         tables      => {
1135             credits => $account->accountlines_id
1136         }
1137     );
1138     is($letter->{content},'<span>Payment</span><span> (Cancelled)</span>', "Include used in notice");
1139 };
1140
1141 subtest 'Dates formatting' => sub {
1142     plan tests => 1;
1143     my $code = 'TEST_DATE';
1144     t::lib::Mocks::mock_preference('dateformat', 'metric'); # MM/DD/YYYY
1145     my $biblio = $builder->build_object(
1146         {
1147             class => 'Koha::Biblios',
1148             value => {
1149                 timestamp   => '2018-12-13 20:21:22',
1150                 datecreated => '2018-12-13'
1151             }
1152         }
1153     );
1154     my $template = <<EOF;
1155 [%- USE KohaDates -%]
1156 [% biblio.timestamp %]
1157 [% biblio.timestamp | \$KohaDates %]
1158 [% biblio.timestamp | \$KohaDates with_hours => 1 %]
1159
1160 [% biblio.datecreated %]
1161 [% biblio.datecreated | \$KohaDates %]
1162 [% biblio.datecreated | \$KohaDates with_hours => 1 %]
1163
1164 [% biblio.timestamp | \$KohaDates dateformat => 'iso' %]
1165 [% KohaDates.output_preference( str => biblio.timestamp, dateformat => 'iso' ) %]
1166 [% KohaDates.output_preference( str => biblio.timestamp, dateformat => 'iso', dateonly => 1 ) %]
1167 EOF
1168     reset_template({ template => $template, code => $code, module => 'test' });
1169     my $letter = GetPreparedLetter(
1170         module => 'test',
1171         letter_code => $code,
1172         tables => {
1173             biblio => $biblio->biblionumber,
1174         }
1175     );
1176     my $expected_content = sprintf("%s\n%s\n%s\n\n%s\n%s\n%s\n\n%s\n%s\n%s\n",
1177         '2018-12-13 20:21:22',
1178         '13/12/2018',
1179         '13/12/2018 20:21',
1180
1181         '2018-12-13',
1182         '13/12/2018',
1183         '13/12/2018 00:00',
1184
1185         '2018-12-13',
1186         '2018-12-13 20:21',
1187         '2018-12-13',
1188     );
1189     is( $letter->{content}, $expected_content );
1190 };
1191
1192 subtest 'Execute TT process in a DB transaction' => sub {
1193     plan tests => 2;
1194     my $code = 'TEST_TXN';
1195     my $library = $builder->build_object( { class => 'Koha::Libraries' } );
1196     my $template = <<EOF;
1197 =[% branch.branchcode %]=
1198 [%~ branch.delete ~%]
1199 EOF
1200     reset_template({ template => $template, code => $code, module => 'test' });
1201     my $letter = GetPreparedLetter(
1202         module      => 'test',
1203         letter_code => $code,
1204         tables      => {
1205             branches => $library->branchcode,
1206         }
1207     );
1208     my $branchcode = $library->branchcode;
1209     like($letter->{content}, qr{=$branchcode=}, 'content generated with the library');
1210     is( ref($library->get_from_storage), 'Koha::Library', 'calling ->delete on the object has not been comitted');
1211
1212 };
1213
1214 subtest '_process_letter croaks on parsing error' => sub {
1215
1216     plan tests => 1;
1217
1218     my $params = {
1219         code => 'TEST_CROAK',
1220         substitute => { count => 42 },
1221     };
1222
1223     my $tt_template = q|[% IF %]|;
1224     eval { process_letter( { template => $tt_template, %$params } ) };
1225     like($@, qr{^ERROR PROCESSING TEMPLATE: });
1226 };
1227
1228 sub reset_template {
1229     my ( $params ) = @_;
1230     my $template   = $params->{template};
1231     my $code       = $params->{code};
1232     my $module     = $params->{module} || 'test_module';
1233
1234     Koha::Notice::Templates->search( { code => $code } )->delete;
1235     Koha::Notice::Template->new(
1236         {
1237             module                 => $module,
1238             code                   => $code,
1239             branchcode             => '',
1240             name                   => $code,
1241             title                  => $code,
1242             message_transport_type => 'email',
1243             content                => $template
1244         }
1245     )->store;
1246 }
1247
1248 sub process_letter {
1249     my ($params)   = @_;
1250     my $template   = $params->{template};
1251     my $tables     = $params->{tables};
1252     my $substitute = $params->{substitute};
1253     my $code       = $params->{code};
1254     my $module     = $params->{module} || 'test_module';
1255     my $branchcode = $params->{branchcode};
1256
1257     reset_template( $params );
1258
1259     my $letter = C4::Letters::GetPreparedLetter(
1260         module      => $module,
1261         letter_code => $code,
1262         branchcode  => '',
1263         tables      => $tables,
1264         substitute  => $substitute,
1265     );
1266     return $letter;
1267 }
1268
1269 $schema->storage->txn_rollback;