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 => 78;
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]->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
182 is( $letters->[0]->{module}, 'my module', 'GetLetters gets the module correctly' );
183 is( $letters->[0]->{code}, 'my code', 'GetLetters gets the code correctly' );
184 is( $letters->[0]->{name}, 'my name', 'GetLetters gets the name correctly' );
188 subtest 'getletter' => sub {
190 t::lib::Mocks::mock_preference('IndependentBranches', 0);
191 my $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
192 is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
193 is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
194 is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
195 is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
196 is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
197 is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
198 is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
199 is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
201 my $context = Test::MockModule->new('C4::Context');
202 $context->mock( 'userenv', sub {
205 branch => "anotherlib" }
208 t::lib::Mocks::mock_preference('IndependentBranches', 1);
209 $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
210 is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
211 is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
212 is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
213 is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
214 is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
215 is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
216 is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
217 is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
219 $context->unmock('userenv');
224 # Regression test for Bug 14206
225 $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 );
226 my $letter14206_a = C4::Letters::getletter('my module', 'my code', 'FFL' );
227 is( $letter14206_a->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type not passed, correct mtt detected' );
228 my $letter14206_b = C4::Letters::getletter('my module', 'my code', 'FFL', 'print');
229 is( $letter14206_b->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type passed, correct mtt detected' );
231 # test for overdue_notices.pl
232 my $overdue_rules = {
233 letter1 => 'my code',
236 my $branchcode = 'FFL';
237 my $letter14206_c = C4::Letters::getletter('my module', $overdue_rules->{"letter$i"}, $branchcode);
238 is( $letter14206_c->{message_transport_type}, 'print', 'Bug 14206 - correct mtt detected for call from overdue_notices.pl' );
241 my $type = 'my type';
242 my $externalid = 'my external id';
243 my $alert_id = C4::Letters::addalert($borrowernumber, $type, $externalid);
244 isnt( $alert_id, undef, 'addalert does not return undef' );
248 my $alerts = C4::Letters::getalert();
249 is( @$alerts, 1, 'getalert should not fail without parameter' );
250 $alerts = C4::Letters::getalert($borrowernumber);
251 is( @$alerts, 1, 'addalert adds an alert' );
252 is( $alerts->[0]->{alertid}, $alert_id, 'addalert returns the alert id correctly' );
253 is( $alerts->[0]->{type}, $type, 'addalert stores the type correctly' );
254 is( $alerts->[0]->{externalid}, $externalid, 'addalert stores the externalid correctly' );
256 $alerts = C4::Letters::getalert($borrowernumber, $type);
257 is( @$alerts, 1, 'getalert returns the correct number of alerts' );
258 $alerts = C4::Letters::getalert($borrowernumber, $type, $externalid);
259 is( @$alerts, 1, 'getalert returns the correct number of alerts' );
260 $alerts = C4::Letters::getalert($borrowernumber, 'another type');
261 is( @$alerts, 0, 'getalert returns the correct number of alerts' );
262 $alerts = C4::Letters::getalert($borrowernumber, $type, 'another external id');
263 is( @$alerts, 0, 'getalert returns the correct number of alerts' );
268 C4::Letters::delalert();
270 isnt( $@, undef, 'delalert without argument returns an error' );
271 $alerts = C4::Letters::getalert($borrowernumber);
272 is( @$alerts, 1, 'delalert without argument does not remove an alert' );
274 C4::Letters::delalert($alert_id);
275 $alerts = C4::Letters::getalert($borrowernumber);
276 is( @$alerts, 0, 'delalert removes an alert' );
280 t::lib::Mocks::mock_preference('OPACBaseURL', 'http://thisisatest.com');
282 my $sms_content = 'This is a SMS for an <<status>>';
283 $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 );
286 borrowers => $borrowernumber,
287 branches => $library->{branchcode},
288 biblio => $biblionumber,
295 itemcallnumber => 'my callnumber1',
299 itemcallnumber => 'my callnumber2',
303 my $prepared_letter = GetPreparedLetter((
304 module => 'my module',
305 branchcode => $library->{branchcode},
306 letter_code => 'my code',
308 substitute => $substitute,
311 my $retrieved_library = Koha::Libraries->find($library->{branchcode});
312 my $my_title_letter = $retrieved_library->branchname . qq| - $substitute->{status}|;
313 my $biblio_timestamp = dt_from_string( GetBiblioData($biblionumber)->{timestamp} );
314 my $my_content_letter = qq|Dear Jane Smith,
315 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.
317 |.$retrieved_library->branchname.qq|
318 |.$retrieved_library->branchaddress1.qq|
319 URL: http://thisisatest.com
321 The following item(s) is/are currently $substitute->{status}:
323 <item> 1. $repeat->[0]->{itemcallnumber}, Barcode: $repeat->[0]->{barcode} </item>
324 <item> 2. $repeat->[1]->{itemcallnumber}, Barcode: $repeat->[1]->{barcode} </item>
326 Thank-you for your prompt attention to this matter.
327 Don't forget your date of birth: | . output_pref({ dt => $date, dateonly => 1 }) . q|.
328 Look at this wonderful biblio timestamp: | . output_pref({ dt => $biblio_timestamp }) . ".\n";
330 is( $prepared_letter->{title}, $my_title_letter, 'GetPreparedLetter returns the title correctly' );
331 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
333 $prepared_letter = GetPreparedLetter((
334 module => 'my module',
335 branchcode => $library->{branchcode},
336 letter_code => 'my code',
338 substitute => $substitute,
340 message_transport_type => 'sms',
342 $my_content_letter = qq|This is a SMS for an $substitute->{status}|;
343 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
345 $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>>.');});
346 $prepared_letter = GetPreparedLetter((
347 module => 'test_date',
349 letter_code => 'test_date',
351 substitute => $substitute,
354 is( $prepared_letter->{content}, q|This one only contains the date: | . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 1' );
356 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp | dateonly>>.' WHERE code = 'test_date';});
357 $prepared_letter = GetPreparedLetter((
358 module => 'test_date',
360 letter_code => 'test_date',
362 substitute => $substitute,
365 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 2' );
367 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp|dateonly >>.' WHERE code = 'test_date';});
368 $prepared_letter = GetPreparedLetter((
369 module => 'test_date',
371 letter_code => 'test_date',
373 substitute => $substitute,
376 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 3' );
378 t::lib::Mocks::mock_preference( 'TimeFormat', '12hr' );
379 my $yesterday_night = $date->clone->add( days => -1 )->set_hour(22);
380 $dbh->do(q|UPDATE biblio SET timestamp = ? WHERE biblionumber = ?|, undef, $yesterday_night, $biblionumber );
381 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp>>.' WHERE code = 'test_date';});
382 $prepared_letter = GetPreparedLetter((
383 module => 'test_date',
385 letter_code => 'test_date',
387 substitute => $substitute,
390 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $yesterday_night }) . q|.|, 'dateonly test 3' );
392 $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>');});
393 $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>');});
395 # Test that _parseletter doesn't modify its parameters bug 15429
397 my $values = { dateexpiry => '2015-12-13', };
398 C4::Letters::_parseletter($prepared_letter, 'borrowers', $values);
399 is( $values->{dateexpiry}, '2015-12-13', "_parseletter doesn't modify its parameters" );
402 my $bookseller = Koha::Acquisition::Bookseller->new(
405 address1 => "bookseller's address",
411 my $booksellerid = $bookseller->id;
413 Koha::Acquisition::Bookseller::Contact->new( { name => 'John Smith', phone => '0123456x1', claimacquisition => 1, orderacquisition => 1, booksellerid => $booksellerid } )->store;
414 Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues => 1, booksellerid => $booksellerid } )->store;
415 my $basketno = NewBasket($booksellerid, 1);
417 my $budgetid = C4::Budgets::AddBudget({
418 budget_code => "budget_code_test_letters",
419 budget_name => "budget_name_test_letters",
422 my $bib = MARC::Record->new();
423 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
425 MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
429 MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
433 ($biblionumber, $biblioitemnumber) = AddBiblio($bib, '');
434 my $order = Koha::Acquisition::Order->new(
436 basketno => $basketno,
438 biblionumber => $biblionumber,
439 budget_id => $budgetid,
442 my $ordernumber = $order->ordernumber;
444 C4::Acquisition::CloseBasket( $basketno );
447 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
448 qr/^Bookseller .* without emails at/,
449 "SendAlerts prints a warning";
450 is($err->{'error'}, 'no_email', "Trying to send an alert when there's no e-mail results in an error");
452 $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
453 $bookseller->contacts->next->email('testemail@mydomain.com')->store;
455 # Ensure that the preference 'LetterLog' is set to logging
456 t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
458 # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
459 C4::Context->_new_userenv('DUMMY');
460 C4::Context->set_userenv( 0, 0, 0, 'firstname', 'surname', $library->{branchcode}, 'My Library', 0, '', '');
461 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
465 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
467 "SendAlerts is using the mocked sendmail routine (orderacquisition)";
468 is($err, 1, "Successfully sent order.");
469 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent order");
470 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Order notice text constructed successfully');
472 $dbh->do(q{DELETE FROM letter WHERE code = 'TESTACQORDER';});
474 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
475 qr/No orderacquisition TESTACQORDER letter transported by email/,
476 "GetPreparedLetter warns about missing notice template";
477 is($err->{'error'}, 'no_letter', "No TESTACQORDER letter was defined.");
482 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
484 "SendAlerts is using the mocked sendmail routine";
486 is($err, 1, "Successfully sent claim");
487 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
488 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Claim notice text constructed successfully');
495 my $internalnotes = 'intnotes';
496 $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
497 my $subscriptionid = NewSubscription(
498 undef, "", undef, undef, undef, $biblionumber,
499 '2013-01-01', 1, undef, undef, undef,
500 undef, undef, undef, undef, undef, undef,
501 1, $notes,undef, '2013-01-01', undef, 1,
502 undef, undef, 0, $internalnotes, 0,
503 undef, undef, 0, undef, '2013-12-31', 0
505 $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>>');});
506 my ($serials_count, @serials) = GetSerials($subscriptionid);
507 my $serial = $serials[0];
509 my $borrowernumber = AddMember(
512 categorycode => $patron_category,
513 branchcode => $library->{branchcode},
514 dateofbirth => $date,
515 email => 'john.smith@test.de',
517 my $alert_id = C4::Letters::addalert($borrowernumber, 'issue', $subscriptionid);
522 $err2 = SendAlerts( 'issue', $serial->{serialid}, 'RLIST' ) }
524 "SendAlerts is using the mocked sendmail routine";
525 is($err2, 1, "Successfully sent serial notification");
526 is($mail{'To'}, 'john.smith@test.de', "mailto correct in sent serial notification");
527 is($mail{'Message'}, 'Silence in the library,'.$subscriptionid.',No. 0', 'Serial notification text constructed successfully');
530 subtest 'GetPreparedLetter' => sub {
533 Koha::Notice::Template->new(
538 message_transport_type => 'email'
543 $letter = C4::Letters::GetPreparedLetter(
545 letter_code => 'test',
548 qr{^ERROR: nothing to substitute},
549 'GetPreparedLetter should warn if tables, substiture and repeat are not set';
551 'No letter should be returned by GetPreparedLetter if something went wrong'
555 $letter = C4::Letters::GetPreparedLetter(
557 letter_code => 'test',
561 qr{^ERROR: nothing to substitute},
562 'GetPreparedLetter should warn if tables, substiture and repeat are not set, even if the key is passed';
564 'No letter should be returned by GetPreparedLetter if something went wrong'
571 subtest 'TranslateNotices' => sub {
574 t::lib::Mocks::mock_preference( 'TranslateNotices', '1' );
578 INSERT INTO letter (module, code, branchcode, name, title, content, message_transport_type, lang) VALUES
579 ('test', 'code', '', 'test', 'a test', 'just a test', 'email', 'default'),
580 ('test', 'code', '', 'test', 'una prueba', 'solo una prueba', 'email', 'es-ES');
583 my $letter = C4::Letters::GetPreparedLetter(
586 letter_code => 'code',
587 message_transport_type => 'email',
588 substitute => $substitute,
593 'GetPreparedLetter should return the default one if the lang parameter is not provided'
596 $letter = C4::Letters::GetPreparedLetter(
599 letter_code => 'code',
600 message_transport_type => 'email',
601 substitute => $substitute,
604 is( $letter->{title}, 'una prueba',
605 'GetPreparedLetter should return the required notice if it exists' );
607 $letter = C4::Letters::GetPreparedLetter(
610 letter_code => 'code',
611 message_transport_type => 'email',
612 substitute => $substitute,
618 'GetPreparedLetter should return the default notice if the one required does not exist'
621 t::lib::Mocks::mock_preference( 'TranslateNotices', '' );
623 $letter = C4::Letters::GetPreparedLetter(
626 letter_code => 'code',
627 message_transport_type => 'email',
628 substitute => $substitute,
631 is( $letter->{title}, 'a test',
632 'GetPreparedLetter should return the default notice if pref disabled but additional language exists' );
636 subtest 'SendQueuedMessages' => sub {
639 t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' );
640 my $patron = Koha::Patrons->find($borrowernumber);
642 INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code)
643 VALUES (?, 'subject', 'content', 'sms', 'pending', 'just_a_code')
644 |, undef, $borrowernumber
646 eval { C4::Letters::SendQueuedMessages(); };
647 is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
649 my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
650 ModMember( borrowernumber => $borrowernumber, smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() );
651 $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
652 C4::Letters::SendQueuedMessages();
653 my $sms_message_address = $schema->resultset('MessageQueue')->search({
654 borrowernumber => $borrowernumber,
656 })->next()->to_address();
657 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address not set' );
658 $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
659 $my_message->{to_address} = 'fixme@kidclamp.iswrong';
660 $message_id = C4::Letters::EnqueueLetter($my_message);
662 my $number_attempted = C4::Letters::SendQueuedMessages({
663 borrowernumber => -1, # -1 still triggers the borrowernumber condition
664 letter_code => 'PASSWORD_RESET',
666 is ( $number_attempted, 0, 'There were no password reset messages for SendQueuedMessages to attempt.' );
668 C4::Letters::SendQueuedMessages();
669 $sms_message_address = $schema->resultset('MessageQueue')->search({
670 borrowernumber => $borrowernumber,
672 })->next()->to_address();
673 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
677 subtest 'get_item_content' => sub {
680 t::lib::Mocks::mock_preference('dateformat', 'metric');
681 t::lib::Mocks::mock_preference('timeformat', '24hr');
683 {date_due => '2041-01-01 12:34', title => 'a first title', barcode => 'a_first_barcode', author => 'a_first_author', itemnumber => 1 },
684 {date_due => '2042-01-02 23:45', title => 'a second title', barcode => 'a_second_barcode', author => 'a_second_author', itemnumber => 2 },
686 my @item_content_fields = qw( date_due title barcode author itemnumber );
689 for my $item ( @items ) {
690 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields } );
693 my $expected_items_content = <<EOF;
694 01/01/2041 12:34\ta first title\ta_first_barcode\ta_first_author\t1
695 02/01/2042 23:45\ta second title\ta_second_barcode\ta_second_author\t2
697 is( $items_content, $expected_items_content, 'get_item_content should return correct items info with time (default)' );
700 $items_content = q||;
701 for my $item ( @items ) {
702 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields, dateonly => 1, } );
705 $expected_items_content = <<EOF;
706 01/01/2041\ta first title\ta_first_barcode\ta_first_author\t1
707 02/01/2042\ta second title\ta_second_barcode\ta_second_author\t2
709 is( $items_content, $expected_items_content, 'get_item_content should return correct items info without time (if dateonly => 1)' );
712 subtest 'Test limit parameter for SendQueuedMessages' => sub {
715 my $dbh = C4::Context->dbh;
717 my $borrowernumber = AddMember(
720 categorycode => $patron_category,
721 branchcode => $library->{branchcode},
722 dateofbirth => $date,
723 smsalertnumber => undef,
726 $dbh->do(q|DELETE FROM message_queue|);
729 'content' => 'a message',
730 'metadata' => 'metadata',
731 'code' => 'TEST_MESSAGE',
732 'content_type' => 'text/plain',
733 'title' => 'message title'
735 'borrowernumber' => $borrowernumber,
736 'to_address' => undef,
737 'message_transport_type' => 'sms',
738 'from_address' => 'from@example.com'
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 C4::Letters::EnqueueLetter($my_message);
745 my $messages_processed = C4::Letters::SendQueuedMessages( { limit => 1 } );
746 is( $messages_processed, 1,
747 'Processed 1 message with limit of 1 and 5 unprocessed messages' );
748 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 2 } );
749 is( $messages_processed, 2,
750 'Processed 2 message with limit of 2 and 4 unprocessed messages' );
751 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 3 } );
752 is( $messages_processed, 2,
753 'Processed 2 message with limit of 3 and 2 unprocessed messages' );