Bug 9302: Use patron-title.inc
[koha.git] / t / db_dependent / Letters.t
blob1a61793d5ecf8c2dc01e170ea2c6a40d92ae98b8
1 #!/usr/bin/perl
3 # This file is part of Koha.
5 # Copyright (C) 2013 Equinox Software, Inc.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use Modern::Perl;
21 use Test::More tests => 77;
22 use Test::MockModule;
23 use Test::Warn;
25 use MARC::Record;
27 my %mail;
28 my $module = new Test::MockModule('Mail::Sendmail');
29 $module->mock(
30 'sendmail',
31 sub {
32 warn "Fake sendmail";
33 %mail = @_;
37 use_ok('C4::Context');
38 use_ok('C4::Members');
39 use_ok('C4::Acquisition');
40 use_ok('C4::Biblio');
41 use_ok('C4::Letters');
42 use t::lib::Mocks;
43 use t::lib::TestBuilder;
44 use Koha::Database;
45 use Koha::DateUtils qw( dt_from_string output_pref );
46 use Koha::Acquisition::Booksellers;
47 use Koha::Acquisition::Bookseller::Contacts;
48 use Koha::Acquisition::Orders;
49 use Koha::Libraries;
50 use Koha::Notice::Templates;
51 my $schema = Koha::Database->schema;
52 $schema->storage->txn_begin();
54 my $builder = t::lib::TestBuilder->new;
55 my $dbh = C4::Context->dbh;
56 $dbh->{RaiseError} = 1;
58 $dbh->do(q|DELETE FROM letter|);
59 $dbh->do(q|DELETE FROM message_queue|);
60 $dbh->do(q|DELETE FROM message_transport_types|);
62 my $library = $builder->build({
63 source => 'Branch',
64 });
65 my $patron_category = $builder->build({ source => 'Category' })->{categorycode};
66 my $date = dt_from_string;
67 my $borrowernumber = AddMember(
68 firstname => 'Jane',
69 surname => 'Smith',
70 categorycode => $patron_category,
71 branchcode => $library->{branchcode},
72 dateofbirth => $date,
73 smsalertnumber => undef,
76 my $marc_record = MARC::Record->new;
77 my( $biblionumber, $biblioitemnumber ) = AddBiblio( $marc_record, '' );
81 # GetMessageTransportTypes
82 my $mtts = C4::Letters::GetMessageTransportTypes();
83 is( @$mtts, 0, 'GetMessageTransportTypes returns the correct number of message types' );
85 $dbh->do(q|
86 INSERT INTO message_transport_types( message_transport_type ) VALUES ('email'), ('phone'), ('print'), ('sms')
87 |);
88 $mtts = C4::Letters::GetMessageTransportTypes();
89 is_deeply( $mtts, ['email', 'phone', 'print', 'sms'], 'GetMessageTransportTypes returns all values' );
92 # EnqueueLetter
93 is( C4::Letters::EnqueueLetter(), undef, 'EnqueueLetter without argument returns undef' );
95 my $my_message = {
96 borrowernumber => $borrowernumber,
97 message_transport_type => 'sms',
98 to_address => undef,
99 from_address => 'from@example.com',
101 my $message_id = C4::Letters::EnqueueLetter($my_message);
102 is( $message_id, undef, 'EnqueueLetter without the letter argument returns undef' );
104 delete $my_message->{message_transport_type};
105 $my_message->{letter} = {
106 content => 'a message',
107 title => 'message title',
108 metadata => 'metadata',
109 code => 'TEST_MESSAGE',
110 content_type => 'text/plain',
113 $message_id = C4::Letters::EnqueueLetter($my_message);
114 is( $message_id, undef, 'EnqueueLetter without the message type argument argument returns undef' );
116 $my_message->{message_transport_type} = 'sms';
117 $message_id = C4::Letters::EnqueueLetter($my_message);
118 ok(defined $message_id && $message_id > 0, 'new message successfully queued');
121 # GetQueuedMessages
122 my $messages = C4::Letters::GetQueuedMessages();
123 is( @$messages, 1, 'GetQueuedMessages without argument returns all the entries' );
125 $messages = C4::Letters::GetQueuedMessages({ borrowernumber => $borrowernumber });
126 is( @$messages, 1, 'one message stored for the borrower' );
127 is( $messages->[0]->{message_id}, $message_id, 'EnqueueLetter returns the message id correctly' );
128 is( $messages->[0]->{borrowernumber}, $borrowernumber, 'EnqueueLetter stores the borrower number correctly' );
129 is( $messages->[0]->{subject}, $my_message->{letter}->{title}, 'EnqueueLetter stores the subject correctly' );
130 is( $messages->[0]->{content}, $my_message->{letter}->{content}, 'EnqueueLetter stores the content correctly' );
131 is( $messages->[0]->{message_transport_type}, $my_message->{message_transport_type}, 'EnqueueLetter stores the message type correctly' );
132 is( $messages->[0]->{status}, 'pending', 'EnqueueLetter stores the status pending correctly' );
135 # SendQueuedMessages
136 my $messages_processed = C4::Letters::SendQueuedMessages( { type => 'email' });
137 is($messages_processed, 0, 'No queued messages processed if type limit passed with unused type');
138 $messages_processed = C4::Letters::SendQueuedMessages( { type => 'sms' });
139 is($messages_processed, 1, 'All queued messages processed, found correct number of messages with type limit');
140 $messages = C4::Letters::GetQueuedMessages({ borrowernumber => $borrowernumber });
142 $messages->[0]->{status},
143 'failed',
144 'message marked failed if tried to send SMS message for borrower with no smsalertnumber set (bug 11208)'
147 # ResendMessage
148 my $resent = C4::Letters::ResendMessage($messages->[0]->{message_id});
149 my $message = C4::Letters::GetMessage( $messages->[0]->{message_id});
150 is( $resent, 1, 'The message should have been resent' );
151 is($message->{status},'pending', 'ResendMessage sets status to pending correctly (bug 12426)');
152 $resent = C4::Letters::ResendMessage($messages->[0]->{message_id});
153 is( $resent, 0, 'The message should not have been resent again' );
154 $resent = C4::Letters::ResendMessage();
155 is( $resent, undef, 'ResendMessage should return undef if not message_id given' );
157 # GetLetters
158 my $letters = C4::Letters::GetLetters();
159 is( @$letters, 0, 'GetLetters returns the correct number of letters' );
161 my $title = q|<<branches.branchname>> - <<status>>|;
162 my $content = q{Dear <<borrowers.firstname>> <<borrowers.surname>>,
163 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.
165 <<branches.branchname>>
166 <<branches.branchaddress1>>
167 URL: <<OPACBaseURL>>
169 The following item(s) is/are currently <<status>>:
171 <item> <<count>>. <<items.itemcallnumber>>, Barcode: <<items.barcode>> </item>
173 Thank-you for your prompt attention to this matter.
174 Don't forget your date of birth: <<borrowers.dateofbirth>>.
175 Look at this wonderful biblio timestamp: <<biblio.timestamp>>.
178 $dbh->do( q|INSERT INTO letter(branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES (?,'my module','my code','my name',1,?,?,'email')|, undef, $library->{branchcode}, $title, $content );
179 $letters = C4::Letters::GetLetters();
180 is( @$letters, 1, 'GetLetters returns the correct number of letters' );
181 is( $letters->[0]->{module}, 'my module', 'GetLetters gets the module correctly' );
182 is( $letters->[0]->{code}, 'my code', 'GetLetters gets the code correctly' );
183 is( $letters->[0]->{name}, 'my name', 'GetLetters gets the name correctly' );
186 # getletter
187 subtest 'getletter' => sub {
188 plan tests => 16;
189 t::lib::Mocks::mock_preference('IndependentBranches', 0);
190 my $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
191 is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
192 is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
193 is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
194 is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
195 is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
196 is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
197 is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
198 is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
200 my $context = Test::MockModule->new('C4::Context');
201 $context->mock( 'userenv', sub {
202 return {
203 flags => 1,
204 branch => "anotherlib" }
207 t::lib::Mocks::mock_preference('IndependentBranches', 1);
208 $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
209 is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
210 is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
211 is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
212 is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
213 is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
214 is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
215 is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
216 is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
218 $context->unmock('userenv');
223 # Regression test for Bug 14206
224 $dbh->do( q|INSERT INTO letter(branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES ('FFL','my module','my code','my name',1,?,?,'print')|, undef, $title, $content );
225 my $letter14206_a = C4::Letters::getletter('my module', 'my code', 'FFL' );
226 is( $letter14206_a->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type not passed, correct mtt detected' );
227 my $letter14206_b = C4::Letters::getletter('my module', 'my code', 'FFL', 'print');
228 is( $letter14206_b->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type passed, correct mtt detected' );
230 # test for overdue_notices.pl
231 my $overdue_rules = {
232 letter1 => 'my code',
234 my $i = 1;
235 my $branchcode = 'FFL';
236 my $letter14206_c = C4::Letters::getletter('my module', $overdue_rules->{"letter$i"}, $branchcode);
237 is( $letter14206_c->{message_transport_type}, 'print', 'Bug 14206 - correct mtt detected for call from overdue_notices.pl' );
239 # addalert
240 my $type = 'my type';
241 my $externalid = 'my external id';
242 my $alert_id = C4::Letters::addalert($borrowernumber, $type, $externalid);
243 isnt( $alert_id, undef, 'addalert does not return undef' );
246 # getalert
247 my $alerts = C4::Letters::getalert();
248 is( @$alerts, 1, 'getalert should not fail without parameter' );
249 $alerts = C4::Letters::getalert($borrowernumber);
250 is( @$alerts, 1, 'addalert adds an alert' );
251 is( $alerts->[0]->{alertid}, $alert_id, 'addalert returns the alert id correctly' );
252 is( $alerts->[0]->{type}, $type, 'addalert stores the type correctly' );
253 is( $alerts->[0]->{externalid}, $externalid, 'addalert stores the externalid correctly' );
255 $alerts = C4::Letters::getalert($borrowernumber, $type);
256 is( @$alerts, 1, 'getalert returns the correct number of alerts' );
257 $alerts = C4::Letters::getalert($borrowernumber, $type, $externalid);
258 is( @$alerts, 1, 'getalert returns the correct number of alerts' );
259 $alerts = C4::Letters::getalert($borrowernumber, 'another type');
260 is( @$alerts, 0, 'getalert returns the correct number of alerts' );
261 $alerts = C4::Letters::getalert($borrowernumber, $type, 'another external id');
262 is( @$alerts, 0, 'getalert returns the correct number of alerts' );
265 # delalert
266 eval {
267 C4::Letters::delalert();
269 isnt( $@, undef, 'delalert without argument returns an error' );
270 $alerts = C4::Letters::getalert($borrowernumber);
271 is( @$alerts, 1, 'delalert without argument does not remove an alert' );
273 C4::Letters::delalert($alert_id);
274 $alerts = C4::Letters::getalert($borrowernumber);
275 is( @$alerts, 0, 'delalert removes an alert' );
278 # GetPreparedLetter
279 t::lib::Mocks::mock_preference('OPACBaseURL', 'http://thisisatest.com');
281 my $sms_content = 'This is a SMS for an <<status>>';
282 $dbh->do( q|INSERT INTO letter(branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES (?,'my module','my code','my name',1,'my title',?,'sms')|, undef, $library->{branchcode}, $sms_content );
284 my $tables = {
285 borrowers => $borrowernumber,
286 branches => $library->{branchcode},
287 biblio => $biblionumber,
289 my $substitute = {
290 status => 'overdue',
292 my $repeat = [
294 itemcallnumber => 'my callnumber1',
295 barcode => '1234',
298 itemcallnumber => 'my callnumber2',
299 barcode => '5678',
302 my $prepared_letter = GetPreparedLetter((
303 module => 'my module',
304 branchcode => $library->{branchcode},
305 letter_code => 'my code',
306 tables => $tables,
307 substitute => $substitute,
308 repeat => $repeat,
310 my $retrieved_library = Koha::Libraries->find($library->{branchcode});
311 my $my_title_letter = $retrieved_library->branchname . qq| - $substitute->{status}|;
312 my $biblio_timestamp = dt_from_string( GetBiblioData($biblionumber)->{timestamp} );
313 my $my_content_letter = qq|Dear Jane Smith,
314 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.
316 |.$retrieved_library->branchname.qq|
317 |.$retrieved_library->branchaddress1.qq|
318 URL: http://thisisatest.com
320 The following item(s) is/are currently $substitute->{status}:
322 <item> 1. $repeat->[0]->{itemcallnumber}, Barcode: $repeat->[0]->{barcode} </item>
323 <item> 2. $repeat->[1]->{itemcallnumber}, Barcode: $repeat->[1]->{barcode} </item>
325 Thank-you for your prompt attention to this matter.
326 Don't forget your date of birth: | . output_pref({ dt => $date, dateonly => 1 }) . q|.
327 Look at this wonderful biblio timestamp: | . output_pref({ dt => $biblio_timestamp }) . ".\n";
329 is( $prepared_letter->{title}, $my_title_letter, 'GetPreparedLetter returns the title correctly' );
330 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
332 $prepared_letter = GetPreparedLetter((
333 module => 'my module',
334 branchcode => $library->{branchcode},
335 letter_code => 'my code',
336 tables => $tables,
337 substitute => $substitute,
338 repeat => $repeat,
339 message_transport_type => 'sms',
341 $my_content_letter = qq|This is a SMS for an $substitute->{status}|;
342 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
344 $dbh->do(q{INSERT INTO letter (module, code, name, title, content) VALUES ('test_date','TEST_DATE','Test dates','A title with a timestamp: <<biblio.timestamp>>','This one only contains the date: <<biblio.timestamp | dateonly>>.');});
345 $prepared_letter = GetPreparedLetter((
346 module => 'test_date',
347 branchcode => '',
348 letter_code => 'test_date',
349 tables => $tables,
350 substitute => $substitute,
351 repeat => $repeat,
353 is( $prepared_letter->{content}, q|This one only contains the date: | . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 1' );
355 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp | dateonly>>.' WHERE code = 'test_date';});
356 $prepared_letter = GetPreparedLetter((
357 module => 'test_date',
358 branchcode => '',
359 letter_code => 'test_date',
360 tables => $tables,
361 substitute => $substitute,
362 repeat => $repeat,
364 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 2' );
366 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp|dateonly >>.' WHERE code = 'test_date';});
367 $prepared_letter = GetPreparedLetter((
368 module => 'test_date',
369 branchcode => '',
370 letter_code => 'test_date',
371 tables => $tables,
372 substitute => $substitute,
373 repeat => $repeat,
375 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 3' );
377 t::lib::Mocks::mock_preference( 'TimeFormat', '12hr' );
378 my $yesterday_night = $date->clone->add( days => -1 )->set_hour(22);
379 $dbh->do(q|UPDATE biblio SET timestamp = ? WHERE biblionumber = ?|, undef, $yesterday_night, $biblionumber );
380 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp>>.' WHERE code = 'test_date';});
381 $prepared_letter = GetPreparedLetter((
382 module => 'test_date',
383 branchcode => '',
384 letter_code => 'test_date',
385 tables => $tables,
386 substitute => $substitute,
387 repeat => $repeat,
389 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $yesterday_night }) . q|.|, 'dateonly test 3' );
391 $dbh->do(q{INSERT INTO letter (module, code, name, title, content) VALUES ('claimacquisition','TESTACQCLAIM','Acquisition Claim','Item Not Received','<<aqbooksellers.name>>|<<aqcontacts.name>>|<order>Ordernumber <<aqorders.ordernumber>> (<<biblio.title>>) (<<aqorders.quantity>> ordered)</order>');});
392 $dbh->do(q{INSERT INTO letter (module, code, name, title, content) VALUES ('orderacquisition','TESTACQORDER','Acquisition Order','Order','<<aqbooksellers.name>>|<<aqcontacts.name>>|<order>Ordernumber <<aqorders.ordernumber>> (<<biblio.title>>) (<<aqorders.quantity>> ordered)</order>');});
394 # Test that _parseletter doesn't modify its parameters bug 15429
396 my $values = { dateexpiry => '2015-12-13', };
397 C4::Letters::_parseletter($prepared_letter, 'borrowers', $values);
398 is( $values->{dateexpiry}, '2015-12-13', "_parseletter doesn't modify its parameters" );
401 my $bookseller = Koha::Acquisition::Bookseller->new(
403 name => "my vendor",
404 address1 => "bookseller's address",
405 phone => "0123456",
406 active => 1,
407 deliverytime => 5,
409 )->store;
410 my $booksellerid = $bookseller->id;
412 Koha::Acquisition::Bookseller::Contact->new( { name => 'John Smith', phone => '0123456x1', claimacquisition => 1, orderacquisition => 1, booksellerid => $booksellerid } )->store;
413 Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues => 1, booksellerid => $booksellerid } )->store;
414 my $basketno = NewBasket($booksellerid, 1);
416 my $budgetid = C4::Budgets::AddBudget({
417 budget_code => "budget_code_test_letters",
418 budget_name => "budget_name_test_letters",
421 my $bib = MARC::Record->new();
422 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
423 $bib->append_fields(
424 MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
426 } else {
427 $bib->append_fields(
428 MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
432 ($biblionumber, $biblioitemnumber) = AddBiblio($bib, '');
433 my $order = Koha::Acquisition::Order->new(
435 basketno => $basketno,
436 quantity => 1,
437 biblionumber => $biblionumber,
438 budget_id => $budgetid,
440 )->store;
441 my $ordernumber = $order->ordernumber;
443 C4::Acquisition::CloseBasket( $basketno );
444 my $err;
445 warning_like {
446 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
447 qr/^Bookseller .* without emails at/,
448 "SendAlerts prints a warning";
449 is($err->{'error'}, 'no_email', "Trying to send an alert when there's no e-mail results in an error");
451 $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
452 $bookseller->contacts->next->email('testemail@mydomain.com')->store;
454 # Ensure that the preference 'LetterLog' is set to logging
455 t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
457 # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
458 C4::Context->_new_userenv('DUMMY');
459 C4::Context->set_userenv( 0, 0, 0, 'firstname', 'surname', $library->{branchcode}, 'My Library', 0, '', '');
460 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
463 warning_is {
464 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
465 "Fake sendmail",
466 "SendAlerts is using the mocked sendmail routine (orderacquisition)";
467 is($err, 1, "Successfully sent order.");
468 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent order");
469 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Order notice text constructed successfully');
471 $dbh->do(q{DELETE FROM letter WHERE code = 'TESTACQORDER';});
472 warning_like {
473 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
474 qr/No orderacquisition TESTACQORDER letter transported by email/,
475 "GetPreparedLetter warns about missing notice template";
476 is($err->{'error'}, 'no_letter', "No TESTACQORDER letter was defined.");
480 warning_is {
481 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
482 "Fake sendmail",
483 "SendAlerts is using the mocked sendmail routine";
485 is($err, 1, "Successfully sent claim");
486 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
487 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Claim notice text constructed successfully');
491 use C4::Serials;
493 my $notes = 'notes';
494 my $internalnotes = 'intnotes';
495 $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
496 my $subscriptionid = NewSubscription(
497 undef, "", undef, undef, undef, $biblionumber,
498 '2013-01-01', 1, undef, undef, undef,
499 undef, undef, undef, undef, undef, undef,
500 1, $notes,undef, '2013-01-01', undef, 1,
501 undef, undef, 0, $internalnotes, 0,
502 undef, undef, 0, undef, '2013-12-31', 0
504 $dbh->do(q{INSERT INTO letter (module, code, name, title, content) VALUES ('serial','RLIST','Serial issue notification','Serial issue notification','<<biblio.title>>,<<subscription.subscriptionid>>,<<serial.serialseq>>');});
505 my ($serials_count, @serials) = GetSerials($subscriptionid);
506 my $serial = $serials[0];
508 my $borrowernumber = AddMember(
509 firstname => 'John',
510 surname => 'Smith',
511 categorycode => $patron_category,
512 branchcode => $library->{branchcode},
513 dateofbirth => $date,
514 email => 'john.smith@test.de',
516 my $alert_id = C4::Letters::addalert($borrowernumber, 'issue', $subscriptionid);
519 my $err2;
520 warning_is {
521 $err2 = SendAlerts( 'issue', $serial->{serialid}, 'RLIST' ) }
522 "Fake sendmail",
523 "SendAlerts is using the mocked sendmail routine";
524 is($err2, 1, "Successfully sent serial notification");
525 is($mail{'To'}, 'john.smith@test.de', "mailto correct in sent serial notification");
526 is($mail{'Message'}, 'Silence in the library,'.$subscriptionid.',No. 0', 'Serial notification text constructed successfully');
529 subtest 'GetPreparedLetter' => sub {
530 plan tests => 4;
532 Koha::Notice::Template->new(
534 module => 'test',
535 code => 'test',
536 branchcode => '',
537 message_transport_type => 'email'
539 )->store;
540 my $letter;
541 warning_like {
542 $letter = C4::Letters::GetPreparedLetter(
543 module => 'test',
544 letter_code => 'test',
547 qr{^ERROR: nothing to substitute},
548 'GetPreparedLetter should warn if tables, substiture and repeat are not set';
549 is( $letter, undef,
550 'No letter should be returned by GetPreparedLetter if something went wrong'
553 warning_like {
554 $letter = C4::Letters::GetPreparedLetter(
555 module => 'test',
556 letter_code => 'test',
557 substitute => {}
560 qr{^ERROR: nothing to substitute},
561 'GetPreparedLetter should warn if tables, substiture and repeat are not set, even if the key is passed';
562 is( $letter, undef,
563 'No letter should be returned by GetPreparedLetter if something went wrong'
570 subtest 'TranslateNotices' => sub {
571 plan tests => 4;
573 t::lib::Mocks::mock_preference( 'TranslateNotices', '1' );
575 $dbh->do(
577 INSERT INTO letter (module, code, branchcode, name, title, content, message_transport_type, lang) VALUES
578 ('test', 'code', '', 'test', 'a test', 'just a test', 'email', 'default'),
579 ('test', 'code', '', 'test', 'una prueba', 'solo una prueba', 'email', 'es-ES');
580 | );
581 my $substitute = {};
582 my $letter = C4::Letters::GetPreparedLetter(
583 module => 'test',
584 tables => $tables,
585 letter_code => 'code',
586 message_transport_type => 'email',
587 substitute => $substitute,
590 $letter->{title},
591 'a test',
592 'GetPreparedLetter should return the default one if the lang parameter is not provided'
595 $letter = C4::Letters::GetPreparedLetter(
596 module => 'test',
597 tables => $tables,
598 letter_code => 'code',
599 message_transport_type => 'email',
600 substitute => $substitute,
601 lang => 'es-ES',
603 is( $letter->{title}, 'una prueba',
604 'GetPreparedLetter should return the required notice if it exists' );
606 $letter = C4::Letters::GetPreparedLetter(
607 module => 'test',
608 tables => $tables,
609 letter_code => 'code',
610 message_transport_type => 'email',
611 substitute => $substitute,
612 lang => 'fr-FR',
615 $letter->{title},
616 'a test',
617 'GetPreparedLetter should return the default notice if the one required does not exist'
620 t::lib::Mocks::mock_preference( 'TranslateNotices', '' );
622 $letter = C4::Letters::GetPreparedLetter(
623 module => 'test',
624 tables => $tables,
625 letter_code => 'code',
626 message_transport_type => 'email',
627 substitute => $substitute,
628 lang => 'es-ES',
630 is( $letter->{title}, 'a test',
631 'GetPreparedLetter should return the default notice if pref disabled but additional language exists' );
635 subtest 'SendQueuedMessages' => sub {
637 plan tests => 4;
638 t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' );
639 my $patron = Koha::Patrons->find($borrowernumber);
640 $dbh->do(q|
641 INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code)
642 VALUES (?, 'subject', 'content', 'sms', 'pending', 'just_a_code')
643 |, undef, $borrowernumber
645 eval { C4::Letters::SendQueuedMessages(); };
646 is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
648 my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
649 ModMember( borrowernumber => $borrowernumber, smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() );
650 $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
651 C4::Letters::SendQueuedMessages();
652 my $sms_message_address = $schema->resultset('MessageQueue')->search({
653 borrowernumber => $borrowernumber,
654 status => 'sent'
655 })->next()->to_address();
656 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address not set' );
657 $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
658 $my_message->{to_address} = 'fixme@kidclamp.iswrong';
659 $message_id = C4::Letters::EnqueueLetter($my_message);
661 my $number_attempted = C4::Letters::SendQueuedMessages({
662 borrowernumber => -1, # -1 still triggers the borrowernumber condition
663 letter_code => 'PASSWORD_RESET',
665 is ( $number_attempted, 0, 'There were no password reset messages for SendQueuedMessages to attempt.' );
667 C4::Letters::SendQueuedMessages();
668 $sms_message_address = $schema->resultset('MessageQueue')->search({
669 borrowernumber => $borrowernumber,
670 status => 'sent'
671 })->next()->to_address();
672 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
676 subtest 'get_item_content' => sub {
677 plan tests => 2;
679 t::lib::Mocks::mock_preference('dateformat', 'metric');
680 t::lib::Mocks::mock_preference('timeformat', '24hr');
681 my @items = (
682 {date_due => '2041-01-01 12:34', title => 'a first title', barcode => 'a_first_barcode', author => 'a_first_author', itemnumber => 1 },
683 {date_due => '2042-01-02 23:45', title => 'a second title', barcode => 'a_second_barcode', author => 'a_second_author', itemnumber => 2 },
685 my @item_content_fields = qw( date_due title barcode author itemnumber );
687 my $items_content;
688 for my $item ( @items ) {
689 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields } );
692 my $expected_items_content = <<EOF;
693 01/01/2041 12:34\ta first title\ta_first_barcode\ta_first_author\t1
694 02/01/2042 23:45\ta second title\ta_second_barcode\ta_second_author\t2
696 is( $items_content, $expected_items_content, 'get_item_content should return correct items info with time (default)' );
699 $items_content = q||;
700 for my $item ( @items ) {
701 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields, dateonly => 1, } );
704 $expected_items_content = <<EOF;
705 01/01/2041\ta first title\ta_first_barcode\ta_first_author\t1
706 02/01/2042\ta second title\ta_second_barcode\ta_second_author\t2
708 is( $items_content, $expected_items_content, 'get_item_content should return correct items info without time (if dateonly => 1)' );
711 subtest 'Test limit parameter for SendQueuedMessages' => sub {
712 plan tests => 3;
714 my $dbh = C4::Context->dbh;
716 my $borrowernumber = AddMember(
717 firstname => 'Jane',
718 surname => 'Smith',
719 categorycode => $patron_category,
720 branchcode => $library->{branchcode},
721 dateofbirth => $date,
722 smsalertnumber => undef,
725 $dbh->do(q|DELETE FROM message_queue|);
726 $my_message = {
727 'letter' => {
728 'content' => 'a message',
729 'metadata' => 'metadata',
730 'code' => 'TEST_MESSAGE',
731 'content_type' => 'text/plain',
732 'title' => 'message title'
734 'borrowernumber' => $borrowernumber,
735 'to_address' => undef,
736 'message_transport_type' => 'sms',
737 'from_address' => 'from@example.com'
739 C4::Letters::EnqueueLetter($my_message);
740 C4::Letters::EnqueueLetter($my_message);
741 C4::Letters::EnqueueLetter($my_message);
742 C4::Letters::EnqueueLetter($my_message);
743 C4::Letters::EnqueueLetter($my_message);
744 my $messages_processed = C4::Letters::SendQueuedMessages( { limit => 1 } );
745 is( $messages_processed, 1,
746 'Processed 1 message with limit of 1 and 5 unprocessed messages' );
747 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 2 } );
748 is( $messages_processed, 2,
749 'Processed 2 message with limit of 2 and 4 unprocessed messages' );
750 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 3 } );
751 is( $messages_processed, 2,
752 'Processed 2 message with limit of 3 and 2 unprocessed messages' );