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>.
22 use Test::More tests => 17;
27 use t::lib::TestBuilder;
35 use Koha::ArticleRequests;
42 use Koha::Subscription;
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'
71 my $biblioitem = Koha::Biblioitem->new(
73 biblionumber => $biblio->id()
77 my $item = Koha::Item->new(
79 biblionumber => $biblio->id(),
80 biblioitemnumber => $biblioitem->id()
84 my $hold = Koha::Hold->new(
86 borrowernumber => $patron->{borrowernumber},
87 biblionumber => $biblio->id()
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();
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(
107 letter_code => 'TEST_PATRON',
109 borrowers => $patron->{borrowernumber},
113 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with scalar' );
115 $prepared_letter = GetPreparedLetter(
118 letter_code => 'TEST_PATRON',
120 borrowers => $patron,
124 is( $prepared_letter->{content}, $patron->{borrowernumber}, 'Patron object used correctly with hashref' );
126 $prepared_letter = GetPreparedLetter(
129 letter_code => 'TEST_PATRON',
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(
141 letter_code => 'TEST_BIBLIO',
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(
153 letter_code => 'TEST_LIBRARY',
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(
165 letter_code => 'TEST_ITEM',
171 is( $prepared_letter->{content}, $item->id(), 'Item object used correctly' );
173 $sth->execute( "TEST_NEWS", "[% news.id %]" );
174 $prepared_letter = GetPreparedLetter(
177 letter_code => 'TEST_NEWS',
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(
189 letter_code => 'TEST_HOLD',
191 reserves => { borrowernumber => $patron->{borrowernumber}, biblionumber => $biblio->id() },
195 is( $prepared_letter->{content}, $hold->id(), 'Hold object used correctly' );
198 $prepared_letter = GetPreparedLetter(
201 letter_code => 'TEST_HOLD',
203 reserves => [ $patron->{borrowernumber}, $biblio->id() ],
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" );
212 $prepared_letter = GetPreparedLetter(
215 letter_code => 'TEST_HOLD',
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(
232 letter_code => 'TEST_SERIAL',
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(
244 letter_code => 'TEST_SUBSCRIPTION',
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(
256 letter_code => 'TEST_SUGGESTION',
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(
268 letter_code => 'TEST_ISSUE',
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(
280 letter_code => 'TEST_MODIFICATION',
282 borrower_modifications => $modification->verification_token,
286 is( $prepared_letter->{content}, $modification->id(), 'Patron modification object used correctly' );
288 subtest 'regression tests' => sub {
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(
297 biblionumber => $biblio1->{biblionumber},
298 biblioitemnumber => $biblioitem1->{biblioitemnumber},
299 barcode => 'a_t_barcode',
300 homebranch => $library->{branchcode},
301 holdingbranch => $library->{branchcode},
303 itemcallnumber => 'itemcallnumber1',
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(
310 biblionumber => $biblio2->{biblionumber},
311 biblioitemnumber => $biblioitem2->{biblioitemnumber},
312 barcode => 'another_t_barcode',
313 homebranch => $library->{branchcode},
314 holdingbranch => $library->{branchcode},
316 itemcallnumber => 'itemcallnumber2',
319 my $biblio3 = Koha::Biblio->new({title => 'Test Biblio 3'})->store->unblessed;
320 my $biblioitem3 = Koha::Biblioitem->new({biblionumber => $biblio3->{biblionumber}})->store()->unblessed;
321 my $item3 = Koha::Item->new(
323 biblionumber => $biblio3->{biblionumber},
324 biblioitemnumber => $biblioitem3->{biblioitemnumber},
325 barcode => 'another_t_barcode_3',
326 homebranch => $library->{branchcode},
327 holdingbranch => $library->{branchcode},
329 itemcallnumber => 'itemcallnumber3',
333 C4::Context->_new_userenv('xxx');
334 C4::Context->set_userenv(0,0,0,'firstname','surname', $library->{branchcode}, 'Midway Public Library', '', '', '');
336 subtest 'ACQ_NOTIF_ON_RECEIV ' => sub {
338 my $code = 'ACQ_NOTIF_ON_RECEIV';
339 my $branchcode = $library->{branchcode};
340 my $order = $builder->build({ source => 'Aqorder' });
343 Dear <<borrowers.firstname>> <<borrowers.surname>>,
344 The order <<aqorders.ordernumber>> (<<biblio.title>>) has been received.
347 my $params = { code => $code, branchcode => $branchcode, tables => { branches => $library, borrowers => $patron, biblio => $biblio1, aqorders => $order } };
348 my $letter = process_letter( { template => $template, %$params });
350 Dear [% borrower.firstname %] [% borrower.surname %],
351 The order [% order.ordernumber %] ([% biblio.title %]) has been received.
354 my $tt_letter = process_letter( { template => $tt_template, %$params });
356 is( $tt_letter->{content}, $letter->{content}, 'Verified letter content' );
359 subtest 'AR_*' => sub {
361 my $code = 'AR_CANCELED';
362 my $branchcode = $library->{branchcode};
365 <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>)
367 Your request for an article from <<biblio.title>> (<<items.barcode>>) has been canceled for the following reason:
369 <<article_requests.notes>>
372 Title: <<article_requests.title>>
373 Author: <<article_requests.author>>
374 Volume: <<article_requests.volume>>
375 Issue: <<article_requests.issue>>
376 Date: <<article_requests.date>>
377 Pages: <<article_requests.pages>>
378 Chapters: <<article_requests.chapters>>
379 Notes: <<article_requests.patron_notes>>
381 reset_template( { template => $template, code => $code, module => 'circulation' } );
382 my $article_request = $builder->build({ source => 'ArticleRequest' });
383 Koha::ArticleRequests->find( $article_request->{id} )->cancel;
384 my $letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
387 [% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])
389 Your request for an article from [% biblio.title %] ([% item.barcode %]) has been canceled for the following reason:
391 [% article_request.notes %]
394 Title: [% article_request.title %]
395 Author: [% article_request.author %]
396 Volume: [% article_request.volume %]
397 Issue: [% article_request.issue %]
398 Date: [% article_request.date %]
399 Pages: [% article_request.pages %]
400 Chapters: [% article_request.chapters %]
401 Notes: [% article_request.patron_notes %]
403 reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
404 Koha::ArticleRequests->find( $article_request->{id} )->cancel;
405 my $tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
406 is( $tt_letter->content, $letter->content, 'Compare AR_* notices' );
407 isnt( $tt_letter->message_id, $letter->message_id, 'Comparing AR_* notices should compare 2 different messages' );
410 subtest 'CHECKOUT+CHECKIN' => sub {
413 my $checkout_code = 'CHECKOUT';
414 my $checkin_code = 'CHECKIN';
416 my $dbh = C4::Context->dbh;
417 # Enable notification for CHECKOUT - Things are hardcoded here but should work with default data
418 $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 6 );
419 my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
420 $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
421 # Enable notification for CHECKIN - Things are hardcoded here but should work with default data
422 $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 5 );
423 $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
424 $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
427 my $checkout_template = q|
428 The following items have been checked out:
432 Thank you for visiting <<branches.branchname>>.
434 reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
435 my $checkin_template = q[
436 The following items have been checked out:
438 <<biblio.title>> was due on <<old_issues.date_due | dateonly>>
440 Thank you for visiting <<branches.branchname>>.
442 reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
444 C4::Circulation::AddIssue( $patron, $item1->{barcode} );
445 my $first_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
446 C4::Circulation::AddIssue( $patron, $item2->{barcode} );
447 my $second_checkout_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
449 AddReturn( $item1->{barcode} );
450 my $first_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
451 AddReturn( $item2->{barcode} );
452 my $second_checkin_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
454 Koha::Notice::Messages->delete;
457 $checkout_template = q|
458 The following items have been checked out:
462 Thank you for visiting [% branch.branchname %].
464 reset_template( { template => $checkout_template, code => $checkout_code, module => 'circulation' } );
465 $checkin_template = q[
466 The following items have been checked out:
468 [% biblio.title %] was due on [% old_checkout.date_due | $KohaDates %]
470 Thank you for visiting [% branch.branchname %].
472 reset_template( { template => $checkin_template, code => $checkin_code, module => 'circulation' } );
474 C4::Circulation::AddIssue( $patron, $item1->{barcode} );
475 my $first_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
476 C4::Circulation::AddIssue( $patron, $item2->{barcode} );
477 my $second_checkout_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
479 AddReturn( $item1->{barcode} );
480 my $first_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
481 AddReturn( $item2->{barcode} );
482 my $second_checkin_tt_letter = Koha::Notice::Messages->search( {}, { order_by => { -desc => 'message_id' } } )->next;
484 is( $first_checkout_tt_letter->content, $first_checkout_letter->content, 'Verify first checkout letter' );
485 is( $second_checkout_tt_letter->content, $second_checkout_letter->content, 'Verify second checkout letter' );
486 is( $first_checkin_tt_letter->content, $first_checkin_letter->content, 'Verify first checkin letter' );
487 is( $second_checkin_tt_letter->content, $second_checkin_letter->content, 'Verify second checkin letter' );
491 subtest 'DUEDGST|count' => sub {
494 my $code = 'DUEDGST';
496 my $dbh = C4::Context->dbh;
497 # Enable notification for DUEDGST - Things are hardcoded here but should work with default data
498 $dbh->do(q|INSERT INTO borrower_message_preferences( borrowernumber, message_attribute_id ) VALUES ( ?, ? )|, undef, $patron->{borrowernumber}, 1 );
499 my $borrower_message_preference_id = $dbh->last_insert_id(undef, undef, "borrower_message_preferences", undef);
500 $dbh->do(q|INSERT INTO borrower_message_transport_preferences( borrower_message_preference_id, message_transport_type) VALUES ( ?, ? )|, undef, $borrower_message_preference_id, 'email' );
504 substitute => { count => 42 },
508 You have <<count>> items due
510 my $letter = process_letter( { template => $template, %$params });
513 You have [% count %] items due
515 my $tt_letter = process_letter( { template => $tt_template, %$params });
516 is( $tt_letter->{content}, $letter->{content}, );
519 subtest 'HOLD_SLIP|dates|today' => sub {
522 my $code = 'HOLD_SLIP';
524 C4::Reserves::AddReserve( $library->{branchcode}, $patron->{borrowernumber}, $biblio1->{biblionumber}, undef, undef, undef, undef, "a note", undef, $item1->{itemnumber}, 'W' );
525 C4::Reserves::AddReserve( $library->{branchcode}, $patron->{borrowernumber}, $biblio2->{biblionumber}, undef, undef, undef, undef, "another note", undef, $item2->{itemnumber} );
527 my $template = <<EOF;
528 <h5>Date: <<today>></h5>
530 <h3> Transfer to/Hold in <<branches.branchname>></h3>
532 <h3><<borrowers.surname>>, <<borrowers.firstname>></h3>
535 <li><<borrowers.cardnumber>></li>
536 <li><<borrowers.phone>></li>
537 <li> <<borrowers.address>><br />
538 <<borrowers.address2>><br />
539 <<borrowers.city>> <<borrowers.zipcode>>
541 <li><<borrowers.email>></li>
544 <h3>ITEM ON HOLD</h3>
545 <h4><<biblio.title>></h4>
546 <h5><<biblio.author>></h5>
548 <li><<items.barcode>></li>
549 <li><<items.itemcallnumber>></li>
550 <li><<reserves.waitingdate>></li>
553 <pre><<reserves.reservenotes>></pre>
557 reset_template( { template => $template, code => $code, module => 'circulation' } );
558 my $letter_for_item1 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio1->{biblionumber} );
559 my $letter_for_item2 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio2->{biblionumber} );
561 my $tt_template = <<EOF;
562 <h5>Date: [% today | \$KohaDates with_hours => 1 %]</h5>
564 <h3> Transfer to/Hold in [% branch.branchname %]</h3>
566 <h3>[% borrower.surname %], [% borrower.firstname %]</h3>
569 <li>[% borrower.cardnumber %]</li>
570 <li>[% borrower.phone %]</li>
571 <li> [% borrower.address %]<br />
572 [% borrower.address2 %]<br />
573 [% borrower.city %] [% borrower.zipcode %]
575 <li>[% borrower.email %]</li>
578 <h3>ITEM ON HOLD</h3>
579 <h4>[% biblio.title %]</h4>
580 <h5>[% biblio.author %]</h5>
582 <li>[% item.barcode %]</li>
583 <li>[% item.itemcallnumber %]</li>
584 <li>[% hold.waitingdate | \$KohaDates %]</li>
587 <pre>[% hold.reservenotes %]</pre>
591 reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
592 my $tt_letter_for_item1 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio1->{biblionumber} );
593 my $tt_letter_for_item2 = C4::Reserves::ReserveSlip( $library->{branchcode}, $patron->{borrowernumber}, $biblio2->{biblionumber} );
595 is( $tt_letter_for_item1->{content}, $letter_for_item1->{content}, );
596 is( $tt_letter_for_item2->{content}, $letter_for_item2->{content}, );
599 subtest 'ISSUESLIP|checkedout|repeat' => sub {
602 my $code = 'ISSUESLIP';
603 my $now = dt_from_string;
604 my $one_minute_ago = dt_from_string->subtract( minutes => 1 );
606 my $branchcode = $library->{branchcode};
609 my $news_item = Koha::NewsItem->new({ branchcode => $branchcode, title => "A wonderful news", content => "This is the wonderful news." })->store;
612 my $template = <<EOF;
613 <h3><<branches.branchname>></h3>
614 Checked out to <<borrowers.title>> <<borrowers.firstname>> <<borrowers.initials>> <<borrowers.surname>> <br />
615 (<<borrowers.cardnumber>>) <br />
622 <<biblio.title>> <br />
623 Barcode: <<items.barcode>><br />
624 Date due: <<issues.date_due | dateonly>><br />
631 <<biblio.title>> <br />
632 Barcode: <<items.barcode>><br />
633 Date due: <<issues.date_due | dateonly>><br />
639 <h4 style="text-align: center; font-style:italic;">News</h4>
641 <div class="newsitem">
642 <h5 style="margin-bottom: 1px; margin-top: 1px"><b><<opac_news.title>></b></h5>
643 <p style="margin-bottom: 1px; margin-top: 1px"><<opac_news.content>></p>
644 <p class="newsfooter" style="font-size: 8pt; font-style:italic; margin-bottom: 1px; margin-top: 1px">Posted on <<opac_news.timestamp>></p>
650 reset_template( { template => $template, code => $code, module => 'circulation' } );
652 my $checkout = C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
653 $checkout->set_columns( { timestamp => $now, issuedate => $one_minute_ago } )->update; # FIXME $checkout is a Koha::Schema::Result::Issues, must be a Koha::Checkout
654 my $first_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
656 $checkout = C4::Circulation::AddIssue( $patron, $item2->{barcode} ); # Add a second checkout
657 $checkout->set_columns( { timestamp => $now, issuedate => $now } )->update;
658 my $yesterday = dt_from_string->subtract( days => 1 );
659 C4::Circulation::AddIssue( $patron, $item3->{barcode}, $yesterday ); # Add an overdue
660 my $second_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
663 AddReturn( $item1->{barcode} );
664 AddReturn( $item2->{barcode} );
665 AddReturn( $item3->{barcode} );
668 my $tt_template = <<EOF;
669 <h3>[% branch.branchname %]</h3>
670 Checked out to [% borrower.title %] [% borrower.firstname %] [% borrower.initials %] [% borrower.surname %] <br />
671 ([% borrower.cardnumber %]) <br />
673 [% today | \$KohaDates with_hours => 1 %]<br />
676 [% FOREACH checkout IN checkouts %]
677 [%~ SET item = checkout.item %]
678 [%~ SET biblio = checkout.item.biblio %]
680 [% biblio.title %] <br />
681 Barcode: [% item.barcode %]<br />
682 Date due: [% checkout.date_due | \$KohaDates %]<br />
687 [% FOREACH overdue IN overdues %]
688 [%~ SET item = overdue.item %]
689 [%~ SET biblio = overdue.item.biblio %]
691 [% biblio.title %] <br />
692 Barcode: [% item.barcode %]<br />
693 Date due: [% overdue.date_due | \$KohaDates %]<br />
699 <h4 style="text-align: center; font-style:italic;">News</h4>
700 [% FOREACH n IN news %]
701 <div class="newsitem">
702 <h5 style="margin-bottom: 1px; margin-top: 1px"><b>[% n.title %]</b></h5>
703 <p style="margin-bottom: 1px; margin-top: 1px">[% n.content %]</p>
704 <p class="newsfooter" style="font-size: 8pt; font-style:italic; margin-bottom: 1px; margin-top: 1px">Posted on [% n.timestamp | \$KohaDates %]</p>
710 reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
712 $checkout = C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
713 $checkout->set_columns( { timestamp => $now, issuedate => $one_minute_ago } )->update;
714 my $first_tt_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
716 $checkout = C4::Circulation::AddIssue( $patron, $item2->{barcode} ); # Add a second checkout
717 $checkout->set_columns( { timestamp => $now, issuedate => $now } )->update;
718 C4::Circulation::AddIssue( $patron, $item3->{barcode}, $yesterday ); # Add an overdue
719 my $second_tt_slip = C4::Members::IssueSlip( $branchcode, $patron->{borrowernumber} );
721 # There is too many line breaks generated by the historic syntax
722 $second_slip->{content} =~ s|</p>\n\n\n<p>|</p>\n\n<p>|s;
724 is( $first_tt_slip->{content}, $first_slip->{content}, );
725 is( $second_tt_slip->{content}, $second_slip->{content}, );
728 AddReturn( $item1->{barcode} );
729 AddReturn( $item2->{barcode} );
730 AddReturn( $item3->{barcode} );
733 subtest 'ODUE|items.content|item' => sub {
738 my $branchcode = $library->{branchcode};
741 # FIXME items.fine does not work with TT notices
743 # <item> should contain Fine: <<items.fine>></item>
744 my $template = <<EOF;
745 Dear <<borrowers.firstname>> <<borrowers.surname>>,
747 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.
749 <<branches.branchname>>
750 <<branches.branchaddress1>>
751 <<branches.branchaddress2>> <<branches.branchaddress3>>
752 Phone: <<branches.branchphone>>
753 Fax: <<branches.branchfax>>
754 Email: <<branches.branchemail>>
756 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.
758 The following item(s) is/are currently overdue:
760 <item>"<<biblio.title>>" by <<biblio.author>>, <<items.itemcallnumber>>, Barcode: <<items.barcode>></item>
764 Thank-you for your prompt attention to this matter.
766 <<branches.branchname>> Staff
769 reset_template( { template => $template, code => $code, module => 'circulation' } );
771 my $yesterday = dt_from_string->subtract( days => 1 );
772 my $two_days_ago = dt_from_string->subtract( days => 2 );
773 my $issue1 = C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
774 my $issue2 = C4::Circulation::AddIssue( $patron, $item2->{barcode}, $yesterday ); # Add an first overdue
775 my $issue3 = C4::Circulation::AddIssue( $patron, $item3->{barcode}, $two_days_ago ); # Add an second overdue
776 $issue1 = Koha::Checkout->_new_from_dbic( $issue1 )->unblessed; # ->unblessed should be enough but AddIssue does not return a Koha::Checkout object
777 $issue2 = Koha::Checkout->_new_from_dbic( $issue2 )->unblessed;
778 $issue3 = Koha::Checkout->_new_from_dbic( $issue3 )->unblessed;
781 my @item_fields = qw( date_due title barcode author itemnumber );
782 my $items_content = C4::Letters::get_item_content( { item => { %$item1, %$biblio1, %$issue1 }, item_content_fields => \@item_fields, dateonly => 1 } );
783 $items_content .= C4::Letters::get_item_content( { item => { %$item2, %$biblio2, %$issue2 }, item_content_fields => \@item_fields, dateonly => 1 } );
784 $items_content .= C4::Letters::get_item_content( { item => { %$item3, %$biblio3, %$issue3 }, item_content_fields => \@item_fields, dateonly => 1 } );
786 my @items = ( $item1, $item2, $item3 );
787 my $letter = C4::Overdues::parse_overdues_letter(
789 letter_code => $code,
790 borrowernumber => $patron->{borrowernumber},
791 branchcode => $library->{branchcode},
794 bib => $library->{branchname},
795 'items.content' => $items_content,
796 count => scalar( @items ),
797 message_transport_type => 'email',
803 AddReturn( $item1->{barcode} );
804 AddReturn( $item2->{barcode} );
805 AddReturn( $item3->{barcode} );
809 my $tt_template = <<EOF;
810 Dear [% borrower.firstname %] [% borrower.surname %],
812 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.
814 [% branch.branchname %]
815 [% branch.branchaddress1 %]
816 [% branch.branchaddress2 %] [% branch.branchaddress3 %]
817 Phone: [% branch.branchphone %]
818 Fax: [% branch.branchfax %]
819 Email: [% branch.branchemail %]
821 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.
823 The following item(s) is/are currently overdue:
825 [% FOREACH overdue IN overdues %]
826 [%~ SET item = overdue.item ~%]
827 "[% item.biblio.title %]" by [% item.biblio.author %], [% item.itemcallnumber %], Barcode: [% item.barcode %]
829 [% FOREACH overdue IN overdues %]
830 [%~ SET item = overdue.item ~%]
831 [% overdue.date_due | \$KohaDates %]\t[% item.biblio.title %]\t[% item.barcode %]\t[% item.biblio.author %]\t[% item.itemnumber %]
834 Thank-you for your prompt attention to this matter.
836 [% branch.branchname %] Staff
839 reset_template( { template => $tt_template, code => $code, module => 'circulation' } );
841 C4::Circulation::AddIssue( $patron, $item1->{barcode} ); # Add a first checkout
842 C4::Circulation::AddIssue( $patron, $item2->{barcode}, $yesterday ); # Add an first overdue
843 C4::Circulation::AddIssue( $patron, $item3->{barcode}, $two_days_ago ); # Add an second overdue
845 my $tt_letter = C4::Overdues::parse_overdues_letter(
847 letter_code => $code,
848 borrowernumber => $patron->{borrowernumber},
849 branchcode => $library->{branchcode},
852 bib => $library->{branchname},
853 'items.content' => $items_content,
854 count => scalar( @items ),
855 message_transport_type => 'email',
860 is( $tt_letter->{content}, $letter->{content}, );
865 subtest 'loops' => sub {
870 subtest 'primary key is AI' => sub {
872 my $patron_1 = $builder->build({ source => 'Borrower' });
873 my $patron_2 = $builder->build({ source => 'Borrower' });
875 my $template = q|[% FOREACH patron IN borrowers %][% patron.surname %][% END %]|;
876 reset_template( { template => $template, code => $code, module => $module } );
877 my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { borrowers => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber} ] } );
878 my $expected_letter = join '', ( $patron_1->{surname}, $patron_2->{surname} );
879 is( $letter->{content}, $expected_letter, );
882 subtest 'foreign key is used' => sub {
884 my $patron_1 = $builder->build({ source => 'Borrower' });
885 my $patron_2 = $builder->build({ source => 'Borrower' });
886 my $checkout_1 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
887 my $checkout_2 = $builder->build({ source => 'Issue', value => { borrowernumber => $patron_1->{borrowernumber} } } );
889 my $template = q|[% FOREACH checkout IN checkouts %][% checkout.issue_id %][% END %]|;
890 reset_template( { template => $template, code => $code, module => $module } );
891 my $letter = GetPreparedLetter( module => $module, letter_code => $code, loops => { issues => [ $checkout_1->{itemnumber}, $checkout_2->{itemnumber} ] } );
892 my $expected_letter = join '', ( $checkout_1->{issue_id}, $checkout_2->{issue_id} );
893 is( $letter->{content}, $expected_letter, );
899 my $template = $params->{template};
900 my $code = $params->{code};
901 my $module = $params->{module} || 'test_module';
903 Koha::Notice::Templates->search( { code => $code } )->delete;
904 Koha::Notice::Template->new(
911 message_transport_type => 'email',
919 my $template = $params->{template};
920 my $tables = $params->{tables};
921 my $substitute = $params->{substitute};
922 my $code = $params->{code};
923 my $module = $params->{module} || 'test_module';
924 my $branchcode = $params->{branchcode};
926 reset_template( $params );
928 my $letter = C4::Letters::GetPreparedLetter(
930 letter_code => $code,
933 substitute => $substitute,