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>.
21 use Test::More tests => 75;
28 my $module = new Test::MockModule('Mail::Sendmail');
37 use_ok('C4::Context');
38 use_ok('C4::Members');
39 use_ok('C4::Acquisition');
41 use_ok('C4::Letters');
43 use t::lib::TestBuilder;
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;
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({
65 my $patron_category = $builder->build({ source => 'Category' })->{categorycode};
66 my $date = dt_from_string;
67 my $borrowernumber = AddMember(
70 categorycode => $patron_category,
71 branchcode => $library->{branchcode},
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' );
86 INSERT INTO message_transport_types( message_transport_type ) VALUES ('email'), ('phone'), ('print'), ('sms')
88 $mtts = C4::Letters::GetMessageTransportTypes();
89 is_deeply( $mtts, ['email', 'phone', 'print', 'sms'], 'GetMessageTransportTypes returns all values' );
93 is( C4::Letters::EnqueueLetter(), undef, 'EnqueueLetter without argument returns undef' );
96 borrowernumber => $borrowernumber,
97 message_transport_type => 'sms',
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');
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' );
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},
144 'message marked failed if tried to send SMS message for borrower with no smsalertnumber set (bug 11208)'
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' );
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>>
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' );
187 subtest 'getletter' => sub {
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 {
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',
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' );
240 my $externalid = 'my external id';
241 my $alert_id = C4::Letters::addalert($borrowernumber, $externalid);
242 isnt( $alert_id, undef, 'addalert does not return undef' );
246 my $alerts = C4::Letters::getalert();
247 is( @$alerts, 1, 'getalert should not fail without parameter' );
248 $alerts = C4::Letters::getalert($borrowernumber);
249 is( @$alerts, 1, 'addalert adds an alert' );
250 is( $alerts->[0]->{alertid}, $alert_id, 'addalert returns the alert id correctly' );
251 is( $alerts->[0]->{externalid}, $externalid, 'addalert stores the externalid correctly' );
253 $alerts = C4::Letters::getalert($borrowernumber);
254 is( @$alerts, 1, 'getalert returns the correct number of alerts' );
255 $alerts = C4::Letters::getalert($borrowernumber, $externalid);
256 is( @$alerts, 1, 'getalert returns the correct number of alerts' );
257 $alerts = C4::Letters::getalert($borrowernumber, 'another external id');
258 is( @$alerts, 0, 'getalert returns the correct number of alerts' );
263 C4::Letters::delalert();
265 isnt( $@, undef, 'delalert without argument returns an error' );
266 $alerts = C4::Letters::getalert($borrowernumber);
267 is( @$alerts, 1, 'delalert without argument does not remove an alert' );
269 C4::Letters::delalert($alert_id);
270 $alerts = C4::Letters::getalert($borrowernumber);
271 is( @$alerts, 0, 'delalert removes an alert' );
275 t::lib::Mocks::mock_preference('OPACBaseURL', 'http://thisisatest.com');
277 my $sms_content = 'This is a SMS for an <<status>>';
278 $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 );
281 borrowers => $borrowernumber,
282 branches => $library->{branchcode},
283 biblio => $biblionumber,
290 itemcallnumber => 'my callnumber1',
294 itemcallnumber => 'my callnumber2',
298 my $prepared_letter = GetPreparedLetter((
299 module => 'my module',
300 branchcode => $library->{branchcode},
301 letter_code => 'my code',
303 substitute => $substitute,
306 my $retrieved_library = Koha::Libraries->find($library->{branchcode});
307 my $my_title_letter = $retrieved_library->branchname . qq| - $substitute->{status}|;
308 my $biblio_timestamp = dt_from_string( GetBiblioData($biblionumber)->{timestamp} );
309 my $my_content_letter = qq|Dear Jane Smith,
310 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.
312 |.$retrieved_library->branchname.qq|
313 |.$retrieved_library->branchaddress1.qq|
314 URL: http://thisisatest.com
316 The following item(s) is/are currently $substitute->{status}:
318 <item> 1. $repeat->[0]->{itemcallnumber}, Barcode: $repeat->[0]->{barcode} </item>
319 <item> 2. $repeat->[1]->{itemcallnumber}, Barcode: $repeat->[1]->{barcode} </item>
321 Thank-you for your prompt attention to this matter.
322 Don't forget your date of birth: | . output_pref({ dt => $date, dateonly => 1 }) . q|.
323 Look at this wonderful biblio timestamp: | . output_pref({ dt => $biblio_timestamp }) . ".\n";
325 is( $prepared_letter->{title}, $my_title_letter, 'GetPreparedLetter returns the title correctly' );
326 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
328 $prepared_letter = GetPreparedLetter((
329 module => 'my module',
330 branchcode => $library->{branchcode},
331 letter_code => 'my code',
333 substitute => $substitute,
335 message_transport_type => 'sms',
337 $my_content_letter = qq|This is a SMS for an $substitute->{status}|;
338 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
340 $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>>.');});
341 $prepared_letter = GetPreparedLetter((
342 module => 'test_date',
344 letter_code => 'test_date',
346 substitute => $substitute,
349 is( $prepared_letter->{content}, q|This one only contains the date: | . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 1' );
351 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp | dateonly>>.' WHERE code = 'test_date';});
352 $prepared_letter = GetPreparedLetter((
353 module => 'test_date',
355 letter_code => 'test_date',
357 substitute => $substitute,
360 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 2' );
362 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp|dateonly >>.' WHERE code = 'test_date';});
363 $prepared_letter = GetPreparedLetter((
364 module => 'test_date',
366 letter_code => 'test_date',
368 substitute => $substitute,
371 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 3' );
373 t::lib::Mocks::mock_preference( 'TimeFormat', '12hr' );
374 my $yesterday_night = $date->clone->add( days => -1 )->set_hour(22);
375 $dbh->do(q|UPDATE biblio SET timestamp = ? WHERE biblionumber = ?|, undef, $yesterday_night, $biblionumber );
376 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp>>.' WHERE code = 'test_date';});
377 $prepared_letter = GetPreparedLetter((
378 module => 'test_date',
380 letter_code => 'test_date',
382 substitute => $substitute,
385 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $yesterday_night }) . q|.|, 'dateonly test 3' );
387 $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>');});
388 $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>');});
390 # Test that _parseletter doesn't modify its parameters bug 15429
392 my $values = { dateexpiry => '2015-12-13', };
393 C4::Letters::_parseletter($prepared_letter, 'borrowers', $values);
394 is( $values->{dateexpiry}, '2015-12-13', "_parseletter doesn't modify its parameters" );
397 my $bookseller = Koha::Acquisition::Bookseller->new(
400 address1 => "bookseller's address",
406 my $booksellerid = $bookseller->id;
408 Koha::Acquisition::Bookseller::Contact->new( { name => 'John Smith', phone => '0123456x1', claimacquisition => 1, orderacquisition => 1, booksellerid => $booksellerid } )->store;
409 Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues => 1, booksellerid => $booksellerid } )->store;
410 my $basketno = NewBasket($booksellerid, 1);
412 my $budgetid = C4::Budgets::AddBudget({
413 budget_code => "budget_code_test_letters",
414 budget_name => "budget_name_test_letters",
417 my $bib = MARC::Record->new();
418 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
420 MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
424 MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
428 ($biblionumber, $biblioitemnumber) = AddBiblio($bib, '');
429 my $order = Koha::Acquisition::Order->new(
431 basketno => $basketno,
433 biblionumber => $biblionumber,
434 budget_id => $budgetid,
437 my $ordernumber = $order->ordernumber;
439 C4::Acquisition::CloseBasket( $basketno );
442 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
443 qr/^Bookseller .* without emails at/,
444 "SendAlerts prints a warning";
445 is($err->{'error'}, 'no_email', "Trying to send an alert when there's no e-mail results in an error");
447 $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
448 $bookseller->contacts->next->email('testemail@mydomain.com')->store;
450 # Ensure that the preference 'LetterLog' is set to logging
451 t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
453 # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
454 C4::Context->_new_userenv('DUMMY');
455 C4::Context->set_userenv( 0, 0, 0, 'firstname', 'surname', $library->{branchcode}, 'My Library', 0, '', '');
456 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
460 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
462 "SendAlerts is using the mocked sendmail routine (orderacquisition)";
463 is($err, 1, "Successfully sent order.");
464 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent order");
465 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Order notice text constructed successfully');
467 $dbh->do(q{DELETE FROM letter WHERE code = 'TESTACQORDER';});
469 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
470 qr/No orderacquisition TESTACQORDER letter transported by email/,
471 "GetPreparedLetter warns about missing notice template";
472 is($err->{'error'}, 'no_letter', "No TESTACQORDER letter was defined.");
477 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
479 "SendAlerts is using the mocked sendmail routine";
481 is($err, 1, "Successfully sent claim");
482 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
483 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Claim notice text constructed successfully');
490 my $internalnotes = 'intnotes';
491 $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
492 my $subscriptionid = NewSubscription(
493 undef, "", undef, undef, undef, $biblionumber,
494 '2013-01-01', 1, undef, undef, undef,
495 undef, undef, undef, undef, undef, undef,
496 1, $notes,undef, '2013-01-01', undef, 1,
497 undef, undef, 0, $internalnotes, 0,
498 undef, undef, 0, undef, '2013-12-31', 0
500 $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>>');});
501 my ($serials_count, @serials) = GetSerials($subscriptionid);
502 my $serial = $serials[0];
504 my $borrowernumber = AddMember(
507 categorycode => $patron_category,
508 branchcode => $library->{branchcode},
509 dateofbirth => $date,
510 email => 'john.smith@test.de',
512 my $alert_id = C4::Letters::addalert($borrowernumber, $subscriptionid);
517 $err2 = SendAlerts( 'issue', $serial->{serialid}, 'RLIST' ) }
519 "SendAlerts is using the mocked sendmail routine";
520 is($err2, 1, "Successfully sent serial notification");
521 is($mail{'To'}, 'john.smith@test.de', "mailto correct in sent serial notification");
522 is($mail{'Message'}, 'Silence in the library,'.$subscriptionid.',No. 0', 'Serial notification text constructed successfully');
525 subtest 'GetPreparedLetter' => sub {
528 Koha::Notice::Template->new(
533 message_transport_type => 'email'
538 $letter = C4::Letters::GetPreparedLetter(
540 letter_code => 'test',
543 qr{^ERROR: nothing to substitute},
544 'GetPreparedLetter should warn if tables, substiture and repeat are not set';
546 'No letter should be returned by GetPreparedLetter if something went wrong'
550 $letter = C4::Letters::GetPreparedLetter(
552 letter_code => 'test',
556 qr{^ERROR: nothing to substitute},
557 'GetPreparedLetter should warn if tables, substiture and repeat are not set, even if the key is passed';
559 'No letter should be returned by GetPreparedLetter if something went wrong'
566 subtest 'TranslateNotices' => sub {
569 t::lib::Mocks::mock_preference( 'TranslateNotices', '1' );
573 INSERT INTO letter (module, code, branchcode, name, title, content, message_transport_type, lang) VALUES
574 ('test', 'code', '', 'test', 'a test', 'just a test', 'email', 'default'),
575 ('test', 'code', '', 'test', 'una prueba', 'solo una prueba', 'email', 'es-ES');
578 my $letter = C4::Letters::GetPreparedLetter(
581 letter_code => 'code',
582 message_transport_type => 'email',
583 substitute => $substitute,
588 'GetPreparedLetter should return the default one if the lang parameter is not provided'
591 $letter = C4::Letters::GetPreparedLetter(
594 letter_code => 'code',
595 message_transport_type => 'email',
596 substitute => $substitute,
599 is( $letter->{title}, 'una prueba',
600 'GetPreparedLetter should return the required notice if it exists' );
602 $letter = C4::Letters::GetPreparedLetter(
605 letter_code => 'code',
606 message_transport_type => 'email',
607 substitute => $substitute,
613 'GetPreparedLetter should return the default notice if the one required does not exist'
616 t::lib::Mocks::mock_preference( 'TranslateNotices', '' );
618 $letter = C4::Letters::GetPreparedLetter(
621 letter_code => 'code',
622 message_transport_type => 'email',
623 substitute => $substitute,
626 is( $letter->{title}, 'a test',
627 'GetPreparedLetter should return the default notice if pref disabled but additional language exists' );
631 subtest 'SendQueuedMessages' => sub {
634 t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' );
635 my $patron = Koha::Patrons->find($borrowernumber);
637 INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code)
638 VALUES (?, 'subject', 'content', 'sms', 'pending', 'just_a_code')
639 |, undef, $borrowernumber
641 eval { C4::Letters::SendQueuedMessages(); };
642 is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
644 my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
645 ModMember( borrowernumber => $borrowernumber, smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() );
646 $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
647 C4::Letters::SendQueuedMessages();
648 my $sms_message_address = $schema->resultset('MessageQueue')->search({
649 borrowernumber => $borrowernumber,
651 })->next()->to_address();
652 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address not set' );
653 $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
654 $my_message->{to_address} = 'fixme@kidclamp.iswrong';
655 $message_id = C4::Letters::EnqueueLetter($my_message);
657 my $number_attempted = C4::Letters::SendQueuedMessages({
658 borrowernumber => -1, # -1 still triggers the borrowernumber condition
659 letter_code => 'PASSWORD_RESET',
661 is ( $number_attempted, 0, 'There were no password reset messages for SendQueuedMessages to attempt.' );
663 C4::Letters::SendQueuedMessages();
664 $sms_message_address = $schema->resultset('MessageQueue')->search({
665 borrowernumber => $borrowernumber,
667 })->next()->to_address();
668 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
672 subtest 'get_item_content' => sub {
675 t::lib::Mocks::mock_preference('dateformat', 'metric');
676 t::lib::Mocks::mock_preference('timeformat', '24hr');
678 {date_due => '2041-01-01 12:34', title => 'a first title', barcode => 'a_first_barcode', author => 'a_first_author', itemnumber => 1 },
679 {date_due => '2042-01-02 23:45', title => 'a second title', barcode => 'a_second_barcode', author => 'a_second_author', itemnumber => 2 },
681 my @item_content_fields = qw( date_due title barcode author itemnumber );
684 for my $item ( @items ) {
685 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields } );
688 my $expected_items_content = <<EOF;
689 01/01/2041 12:34\ta first title\ta_first_barcode\ta_first_author\t1
690 02/01/2042 23:45\ta second title\ta_second_barcode\ta_second_author\t2
692 is( $items_content, $expected_items_content, 'get_item_content should return correct items info with time (default)' );
695 $items_content = q||;
696 for my $item ( @items ) {
697 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields, dateonly => 1, } );
700 $expected_items_content = <<EOF;
701 01/01/2041\ta first title\ta_first_barcode\ta_first_author\t1
702 02/01/2042\ta second title\ta_second_barcode\ta_second_author\t2
704 is( $items_content, $expected_items_content, 'get_item_content should return correct items info without time (if dateonly => 1)' );
707 subtest 'Test limit parameter for SendQueuedMessages' => sub {
710 my $dbh = C4::Context->dbh;
712 my $borrowernumber = AddMember(
715 categorycode => $patron_category,
716 branchcode => $library->{branchcode},
717 dateofbirth => $date,
718 smsalertnumber => undef,
721 $dbh->do(q|DELETE FROM message_queue|);
724 'content' => 'a message',
725 'metadata' => 'metadata',
726 'code' => 'TEST_MESSAGE',
727 'content_type' => 'text/plain',
728 'title' => 'message title'
730 'borrowernumber' => $borrowernumber,
731 'to_address' => undef,
732 'message_transport_type' => 'sms',
733 'from_address' => 'from@example.com'
735 C4::Letters::EnqueueLetter($my_message);
736 C4::Letters::EnqueueLetter($my_message);
737 C4::Letters::EnqueueLetter($my_message);
738 C4::Letters::EnqueueLetter($my_message);
739 C4::Letters::EnqueueLetter($my_message);
740 my $messages_processed = C4::Letters::SendQueuedMessages( { limit => 1 } );
741 is( $messages_processed, 1,
742 'Processed 1 message with limit of 1 and 5 unprocessed messages' );
743 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 2 } );
744 is( $messages_processed, 2,
745 'Processed 2 message with limit of 2 and 4 unprocessed messages' );
746 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 3 } );
747 is( $messages_processed, 2,
748 'Processed 2 message with limit of 3 and 2 unprocessed messages' );