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'})->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
},
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
},
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 {
323 my $code = 'ACQ_NOTIF_ON_RECEIV';
324 my $branchcode = $library->{branchcode
};
325 my $order = $builder->build({ source
=> 'Aqorder' });
328 Dear
<<borrowers.firstname>> <<borrowers.surname
>>,
329 The order
<<aqorders.ordernumber>> (<<biblio.title>>) has been received.
332 my $params = { code => $code, branchcode => $branchcode, tables => { branches => $library, borrowers => $patron, biblio => $biblio1, aqorders
=> $order } };
333 my $letter = process_letter
( { template
=> $template, %$params });
335 Dear
[% borrower
.firstname
%] [% borrower
.surname
%],
336 The order
[% order
.ordernumber
%] ([% biblio
.title
%]) has been received
.
339 my $tt_letter = process_letter
( { template
=> $tt_template, %$params });
341 is
( $tt_letter->{content
}, $letter->{content
}, );
344 subtest
'AR_*' => sub {
346 my $code = 'AR_CANCELED';
347 my $branchcode = $library->{branchcode
};
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>>
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;
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
%]
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 {
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' );
412 my $checkout_template = q
|
413 The following items have been checked out
:
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:
423 <<biblio.title
>> was due on
<<old_issues.date_due | dateonly>>
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;
442 $checkout_template = q|
443 The following items have been checked out:
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:
453 [% biblio.title %] was due on [% old_checkout.date_due | $KohaDates %]
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 {
482 subtest 'primary key is AI' => sub {
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 {
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, );
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(
523 message_transport_type => 'email',
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(
542 letter_code => $code,
545 substitute => $substitute,