Bug 17964: Add old_issues
[koha.git] / t / db_dependent / Letters / TemplateToolkit.t
blob1161690e1e993d81d764a2141eb2f3a487cf0e76
1 #!/usr/bin/perl
3 # This file is part of Koha.
5 # Copyright (C) 2016 ByWater Solutions
6 # Copyright (C) 2017 Koha Development Team
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.
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.
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>.
21 use Modern::Perl;
22 use Test::More tests => 17;
23 use Test::Warn;
25 use MARC::Record;
27 use t::lib::TestBuilder;
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;
49 my $schema = Koha::Database->schema;
50 $schema->storage->txn_begin();
52 my $builder = t::lib::TestBuilder->new();
54 my $dbh = C4::Context->dbh;
55 $dbh->{RaiseError} = 1;
57 $dbh->do(q|DELETE FROM letter|);
59 my $date = dt_from_string;
61 my $library = $builder->build( { source => 'Branch' } );
62 my $patron = $builder->build( { source => 'Borrower' } );
63 my $patron2 = $builder->build( { source => 'Borrower' } );
65 my $biblio = Koha::Biblio->new(
67 title => 'Test Biblio'
69 )->store();
71 my $biblioitem = Koha::Biblioitem->new(
73 biblionumber => $biblio->id()
75 )->store();
77 my $item = Koha::Item->new(
79 biblionumber => $biblio->id(),
80 biblioitemnumber => $biblioitem->id()
82 )->store();
84 my $hold = Koha::Hold->new(
86 borrowernumber => $patron->{borrowernumber},
87 biblionumber => $biblio->id()
89 )->store();
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();
98 my $prepared_letter;
100 my $sth =
101 $dbh->prepare(q{INSERT INTO letter (module, code, name, title, content) VALUES ('test',?,'Test','Test',?)});
103 $sth->execute( "TEST_PATRON", "[% borrower.id %]" );
104 $prepared_letter = GetPreparedLetter(
106 module => 'test',
107 letter_code => 'TEST_PATRON',
108 tables => {
109 borrowers => $patron->{borrowernumber},
113 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with scalar' );
115 $prepared_letter = GetPreparedLetter(
117 module => 'test',
118 letter_code => 'TEST_PATRON',
119 tables => {
120 borrowers => $patron,
124 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with hashref' );
126 $prepared_letter = GetPreparedLetter(
128 module => 'test',
129 letter_code => 'TEST_PATRON',
130 tables => {
131 borrowers => [ $patron->{borrowernumber} ],
135 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with arrayref' );
137 $sth->execute( "TEST_BIBLIO", "[% biblio.id %]" );
138 $prepared_letter = GetPreparedLetter(
140 module => 'test',
141 letter_code => 'TEST_BIBLIO',
142 tables => {
143 biblio => $biblio->id(),
147 is( $prepared_letter->{content}, $biblio->id, 'Biblio object used correctly' );
149 $sth->execute( "TEST_LIBRARY", "[% branch.id %]" );
150 $prepared_letter = GetPreparedLetter(
152 module => 'test',
153 letter_code => 'TEST_LIBRARY',
154 tables => {
155 branches => $library->{branchcode}
159 is( $prepared_letter->{content}, $library->{branchcode}, 'Library object used correctly' );
161 $sth->execute( "TEST_ITEM", "[% item.id %]" );
162 $prepared_letter = GetPreparedLetter(
164 module => 'test',
165 letter_code => 'TEST_ITEM',
166 tables => {
167 items => $item->id()
171 is( $prepared_letter->{content}, $item->id(), 'Item object used correctly' );
173 $sth->execute( "TEST_NEWS", "[% news.id %]" );
174 $prepared_letter = GetPreparedLetter(
176 module => 'test',
177 letter_code => 'TEST_NEWS',
178 tables => {
179 opac_news => $news->id()
183 is( $prepared_letter->{content}, $news->id(), 'News object used correctly' );
185 $sth->execute( "TEST_HOLD", "[% hold.id %]" );
186 $prepared_letter = GetPreparedLetter(
188 module => 'test',
189 letter_code => 'TEST_HOLD',
190 tables => {
191 reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $biblio->id() },
195 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly' );
197 eval {
198 $prepared_letter = GetPreparedLetter(
200 module => 'test',
201 letter_code => 'TEST_HOLD',
202 tables => {
203 reserves => [ $patron->{borrowernumber}, $biblio->id() ],
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" );
211 # Bug 16942
212 $prepared_letter = GetPreparedLetter(
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,
226 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly' );
228 $sth->execute( "TEST_SERIAL", "[% serial.id %]" );
229 $prepared_letter = GetPreparedLetter(
231 module => 'test',
232 letter_code => 'TEST_SERIAL',
233 tables => {
234 serial => $serial->id()
238 is( $prepared_letter->{content}, $serial->id(), 'Serial object used correctly' );
240 $sth->execute( "TEST_SUBSCRIPTION", "[% subscription.id %]" );
241 $prepared_letter = GetPreparedLetter(
243 module => 'test',
244 letter_code => 'TEST_SUBSCRIPTION',
245 tables => {
246 subscription => $subscription->id()
250 is( $prepared_letter->{content}, $subscription->id(), 'Subscription object used correctly' );
252 $sth->execute( "TEST_SUGGESTION", "[% suggestion.id %]" );
253 $prepared_letter = GetPreparedLetter(
255 module => 'test',
256 letter_code => 'TEST_SUGGESTION',
257 tables => {
258 suggestions => $suggestion->id()
262 is( $prepared_letter->{content}, $suggestion->id(), 'Suggestion object used correctly' );
264 $sth->execute( "TEST_ISSUE", "[% checkout.id %]" );
265 $prepared_letter = GetPreparedLetter(
267 module => 'test',
268 letter_code => 'TEST_ISSUE',
269 tables => {
270 issues => $item->id()
274 is( $prepared_letter->{content}, $checkout->id(), 'Checkout object used correctly' );
276 $sth->execute( "TEST_MODIFICATION", "[% patron_modification.id %]" );
277 $prepared_letter = GetPreparedLetter(
279 module => 'test',
280 letter_code => 'TEST_MODIFICATION',
281 tables => {
282 borrower_modifications => $modification->verification_token,
286 is( $prepared_letter->{content}, $modification->id(), 'Patron modification object used correctly' );
288 subtest 'regression tests' => sub {
289 plan tests => 3;
291 my $library = $builder->build( { source => 'Branch' } );
292 my $patron = $builder->build( { source => 'Borrower' } );
293 my $biblio1 = Koha::Biblio->new({title => 'Test Biblio 1'})->store->unblessed;
294 my $biblioitem1 = Koha::Biblioitem->new({biblionumber => $biblio1->{biblionumber}})->store()->unblessed;
295 my $item1 = Koha::Item->new(
297 biblionumber => $biblio1->{biblionumber},
298 biblioitemnumber => $biblioitem1->{biblioitemnumber},
299 barcode => 'a_t_barcode',
300 homebranch => $library->{branchcode},
301 holdingbranch => $library->{branchcode},
302 itype => 'BK',
304 )->store->unblessed;
305 my $biblio2 = Koha::Biblio->new({title => 'Test Biblio 2'})->store->unblessed;
306 my $biblioitem2 = Koha::Biblioitem->new({biblionumber => $biblio2->{biblionumber}})->store()->unblessed;
307 my $item2 = Koha::Item->new(
309 biblionumber => $biblio2->{biblionumber},
310 biblioitemnumber => $biblioitem2->{biblioitemnumber},
311 barcode => 'another_t_barcode',
312 homebranch => $library->{branchcode},
313 holdingbranch => $library->{branchcode},
314 itype => 'BK',
316 )->store->unblessed;
318 C4::Context->_new_userenv('xxx');
319 C4::Context->set_userenv(0,0,0,'firstname','surname', $library->{branchcode}, 'Midway Public Library', '', '', '');
321 subtest 'ACQ_NOTIF_ON_RECEIV ' => sub {
322 plan tests => 1;
323 my $code = 'ACQ_NOTIF_ON_RECEIV';
324 my $branchcode = $library->{branchcode};
325 my $order = $builder->build({ source => 'Aqorder' });
327 my $template = q|
328 Dear <<borrowers.firstname>> <<borrowers.surname>>,
329 The order <<aqorders.ordernumber>> (<<biblio.title>>) has been received.
330 Your library.
332 my $params = { code => $code, branchcode => $branchcode, tables => { branches => $library, borrowers => $patron, biblio => $biblio1, aqorders => $order } };
333 my $letter = process_letter( { template => $template, %$params });
334 my $tt_template = q|
335 Dear [% borrower.firstname %] [% borrower.surname %],
336 The order [% order.ordernumber %] ([% biblio.title %]) has been received.
337 Your library.
339 my $tt_letter = process_letter( { template => $tt_template, %$params });
341 is( $tt_letter->{content}, $letter->{content}, );
344 subtest 'AR_*' => sub {
345 plan tests => 2;
346 my $code = 'AR_CANCELED';
347 my $branchcode = $library->{branchcode};
349 my $template = q|
350 <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)
352 Your request for an article from <<biblio.title>> (<<items.barcode>>) has been canceled for the following reason:
354 <<article_requests.notes>>
356 Article requested:
357 Title: <<article_requests.title>>
358 Author: <<article_requests.author>>
359 Volume: <<article_requests.volume>>
360 Issue: <<article_requests.issue>>
361 Date: <<article_requests.date>>
362 Pages: <<article_requests.pages>>
363 Chapters: <<article_requests.chapters>>
364 Notes: <<article_requests.patron_notes>>
366 reset_template( { template => $template, code => $code, module => 'circulation' } );
367 my $article_request = $builder->build({ source => 'ArticleRequest' });
368 Koha::ArticleRequests->find( $article_request->{id} )->cancel;
369 my $letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
371 my $tt_template = q|
372 [% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])
374 Your request for an article from [% biblio.title %] ([% item.barcode %]) has been canceled for the following reason:
376 [% article_request.notes %]
378 Article requested:
379 Title: [% article_request.title %]
380 Author: [% article_request.author %]
381 Volume: [% article_request.volume %]
382 Issue: [% article_request.issue %]
383 Date: [% article_request.date %]
384 Pages: [% article_request.pages %]
385 Chapters: [% article_request.chapters %]
386 Notes: [% article_request.patron_notes %]
388 reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
389 Koha::ArticleRequests->find( $article_request->{id} )->cancel;
390 my $tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
391 is( $tt_letter->content, $letter->content, 'Compare AR_* notices' );
392 isnt( $tt_letter->message_id, $letter->message_id, 'Comparing AR_* notices should compare 2 different messages' );
395 subtest 'CHECKOUT+CHECKIN' => sub {
396 plan tests => 4;
398 my $checkout_code = 'CHECKOUT';
399 my $checkin_code = 'CHECKIN';
401 my $dbh = C4::Context->dbh;
402 # Enable notification for CHECKOUT - Things are hardcoded here but should work with default data
403 $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 6 );
404 my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
405 $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
406 # Enable notification for CHECKIN - Things are hardcoded here but should work with default data
407 $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 5 );
408 $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
409 $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
411 # historic syntax
412 my $checkout_template = q|
413 The following items have been checked out:
414 ----
415 <<biblio.title>>
416 ----
417 Thank you for visiting <<branches.branchname>>.
419 reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
420 my $checkin_template = q[
421 The following items have been checkin out:
422 ----
423 <<biblio.title>> was due on <<old_issues.date_due | dateonly>>
424 ----
425 Thank you for visiting <<branches.branchname>>.
427 reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
429 C4::Circulation::AddIssue( $patron, $item1->{barcode} );
430 my $first_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
431 C4::Circulation::AddIssue( $patron, $item2->{barcode} );
432 my $second_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
434 AddReturn( $item1->{barcode} );
435 my $first_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
436 AddReturn( $item2->{barcode} );
437 my $second_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
439 Koha::Notice::Messages->delete;
441 # TT syntax
442 $checkout_template = q|
443 The following items have been checked out:
444 ----
445 [% biblio.title %]
446 ----
447 Thank you for visiting [% branch.branchname %].
449 reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
450 $checkin_template = q[
451 The following items have been checkin out:
452 ----
453 [% biblio.title %] was due on [% old_checkout.date_due | $KohaDates %]
454 ----
455 Thank you for visiting [% branch.branchname %].
457 reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
459 C4::Circulation::AddIssue( $patron, $item1->{barcode} );
460 my $first_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
461 C4::Circulation::AddIssue( $patron, $item2->{barcode} );
462 my $second_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
464 AddReturn( $item1->{barcode} );
465 my $first_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
466 AddReturn( $item2->{barcode} );
467 my $second_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
469 is( $first_checkout_tt_letter->content, $first_checkout_letter->content, );
470 is( $second_checkout_tt_letter->content, $second_checkout_letter->content, );
471 is( $first_checkin_tt_letter->content, $first_checkin_letter->content, );
472 is( $second_checkin_tt_letter->content, $second_checkin_letter->content, );
477 subtest 'loops' => sub {
478 plan tests => 2;
479 my $code = "TEST";
480 my $module = "TEST";
482 subtest 'primary key is AI' => sub {
483 plan tests => 1;
484 my $patron_1 = $builder->build({ source => 'Borrower' });
485 my $patron_2 = $builder->build({ source => 'Borrower' });
487 my $template = q|[% FOREACH patron IN borrowers %][% patron.surname %][% END %]|;
488 reset_template( { template => $template, code => $code, module => $module } );
489 my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { borrowers => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber} ] } );
490 my $expected_letter = join '', ( $patron_1->{surname}, $patron_2->{surname} );
491 is( $letter->{content}, $expected_letter, );
494 subtest 'foreign key is used' => sub {
495 plan tests => 1;
496 my $patron_1 = $builder->build({ source => 'Borrower' });
497 my $patron_2 = $builder->build({ source => 'Borrower' });
498 my $checkout_1 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
499 my $checkout_2 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
501 my $template = q|[% FOREACH checkout IN checkouts %][% checkout.issue_id %][% END %]|;
502 reset_template( { template => $template, code => $code, module => $module } );
503 my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { issues => [ $checkout_1->{itemnumber}, $checkout_2->{itemnumber} ] } );
504 my $expected_letter = join '', ( $checkout_1->{issue_id}, $checkout_2->{issue_id} );
505 is( $letter->{content}, $expected_letter, );
509 sub reset_template {
510 my ( $params ) = @_;
511 my $template = $params->{template};
512 my $code = $params->{code};
513 my $module = $params->{module} || 'test_module';
515 Koha::Notice::Templates->search( { code => $code } )->delete;
516 Koha::Notice::Template->new(
518 module => $module,
519 code => $code,
520 branchcode => '',
521 name => $code,
522 title => $code,
523 message_transport_type => 'email',
524 content => $template
526 )->store;
529 sub process_letter {
530 my ($params) = @_;
531 my $template = $params->{template};
532 my $tables = $params->{tables};
533 my $substitute = $params->{substitute};
534 my $code = $params->{code};
535 my $module = $params->{module} || 'test_module';
536 my $branchcode = $params->{branchcode};
538 reset_template( $params );
540 my $letter = C4::Letters::GetPreparedLetter(
541 module => $module,
542 letter_code => $code,
543 branchcode => '',
544 tables => $tables,
545 substitute => $substitute,
547 return $letter;