Bug 7614: Consider transfer limits in Koha::Template::Plugin::Branches
[koha.git] / t / db_dependent / Letters.t
blobf758bbc9bed079dfef82d1d553b44772cc0e5713
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 => 65;
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 use Koha::Patrons;
52 use Koha::Subscriptions;
53 my $schema = Koha::Database->schema;
54 $schema->storage->txn_begin();
56 my $builder = t::lib::TestBuilder->new;
57 my $dbh = C4::Context->dbh;
58 $dbh->{RaiseError} = 1;
60 $dbh->do(q|DELETE FROM letter|);
61 $dbh->do(q|DELETE FROM message_queue|);
62 $dbh->do(q|DELETE FROM message_transport_types|);
64 my $library = $builder->build({
65 source => 'Branch',
66 });
67 my $patron_category = $builder->build({ source => 'Category' })->{categorycode};
68 my $date = dt_from_string;
69 my $borrowernumber = Koha::Patron->new({
70 firstname => 'Jane',
71 surname => 'Smith',
72 categorycode => $patron_category,
73 branchcode => $library->{branchcode},
74 dateofbirth => $date,
75 smsalertnumber => undef,
76 })->store->borrowernumber;
78 my $marc_record = MARC::Record->new;
79 my( $biblionumber, $biblioitemnumber ) = AddBiblio( $marc_record, '' );
83 # GetMessageTransportTypes
84 my $mtts = C4::Letters::GetMessageTransportTypes();
85 is( @$mtts, 0, 'GetMessageTransportTypes returns the correct number of message types' );
87 $dbh->do(q|
88 INSERT INTO message_transport_types( message_transport_type ) VALUES ('email'), ('phone'), ('print'), ('sms')
89 |);
90 $mtts = C4::Letters::GetMessageTransportTypes();
91 is_deeply( $mtts, ['email', 'phone', 'print', 'sms'], 'GetMessageTransportTypes returns all values' );
94 # EnqueueLetter
95 is( C4::Letters::EnqueueLetter(), undef, 'EnqueueLetter without argument returns undef' );
97 my $my_message = {
98 borrowernumber => $borrowernumber,
99 message_transport_type => 'sms',
100 to_address => undef,
101 from_address => 'from@example.com',
103 my $message_id = C4::Letters::EnqueueLetter($my_message);
104 is( $message_id, undef, 'EnqueueLetter without the letter argument returns undef' );
106 delete $my_message->{message_transport_type};
107 $my_message->{letter} = {
108 content => 'a message',
109 title => 'message title',
110 metadata => 'metadata',
111 code => 'TEST_MESSAGE',
112 content_type => 'text/plain',
115 $message_id = C4::Letters::EnqueueLetter($my_message);
116 is( $message_id, undef, 'EnqueueLetter without the message type argument argument returns undef' );
118 $my_message->{message_transport_type} = 'sms';
119 $message_id = C4::Letters::EnqueueLetter($my_message);
120 ok(defined $message_id && $message_id > 0, 'new message successfully queued');
123 # GetQueuedMessages
124 my $messages = C4::Letters::GetQueuedMessages();
125 is( @$messages, 1, 'GetQueuedMessages without argument returns all the entries' );
127 $messages = C4::Letters::GetQueuedMessages({ borrowernumber => $borrowernumber });
128 is( @$messages, 1, 'one message stored for the borrower' );
129 is( $messages->[0]->{message_id}, $message_id, 'EnqueueLetter returns the message id correctly' );
130 is( $messages->[0]->{borrowernumber}, $borrowernumber, 'EnqueueLetter stores the borrower number correctly' );
131 is( $messages->[0]->{subject}, $my_message->{letter}->{title}, 'EnqueueLetter stores the subject correctly' );
132 is( $messages->[0]->{content}, $my_message->{letter}->{content}, 'EnqueueLetter stores the content correctly' );
133 is( $messages->[0]->{message_transport_type}, $my_message->{message_transport_type}, 'EnqueueLetter stores the message type correctly' );
134 is( $messages->[0]->{status}, 'pending', 'EnqueueLetter stores the status pending correctly' );
137 # SendQueuedMessages
138 my $messages_processed = C4::Letters::SendQueuedMessages( { type => 'email' });
139 is($messages_processed, 0, 'No queued messages processed if type limit passed with unused type');
140 $messages_processed = C4::Letters::SendQueuedMessages( { type => 'sms' });
141 is($messages_processed, 1, 'All queued messages processed, found correct number of messages with type limit');
142 $messages = C4::Letters::GetQueuedMessages({ borrowernumber => $borrowernumber });
144 $messages->[0]->{status},
145 'failed',
146 'message marked failed if tried to send SMS message for borrower with no smsalertnumber set (bug 11208)'
149 # ResendMessage
150 my $resent = C4::Letters::ResendMessage($messages->[0]->{message_id});
151 my $message = C4::Letters::GetMessage( $messages->[0]->{message_id});
152 is( $resent, 1, 'The message should have been resent' );
153 is($message->{status},'pending', 'ResendMessage sets status to pending correctly (bug 12426)');
154 $resent = C4::Letters::ResendMessage($messages->[0]->{message_id});
155 is( $resent, 0, 'The message should not have been resent again' );
156 $resent = C4::Letters::ResendMessage();
157 is( $resent, undef, 'ResendMessage should return undef if not message_id given' );
159 # GetLetters
160 my $letters = C4::Letters::GetLetters();
161 is( @$letters, 0, 'GetLetters returns the correct number of letters' );
163 my $title = q|<<branches.branchname>> - <<status>>|;
164 my $content = q{Dear <<borrowers.firstname>> <<borrowers.surname>>,
165 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.
167 <<branches.branchname>>
168 <<branches.branchaddress1>>
169 URL: <<OPACBaseURL>>
171 The following item(s) is/are currently <<status>>:
173 <item> <<count>>. <<items.itemcallnumber>>, Barcode: <<items.barcode>> </item>
175 Thank-you for your prompt attention to this matter.
176 Don't forget your date of birth: <<borrowers.dateofbirth>>.
177 Look at this wonderful biblio timestamp: <<biblio.timestamp>>.
180 $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 );
181 $letters = C4::Letters::GetLetters();
182 is( @$letters, 1, 'GetLetters returns the correct number of letters' );
183 is( $letters->[0]->{module}, 'my module', 'GetLetters gets the module correctly' );
184 is( $letters->[0]->{code}, 'my code', 'GetLetters gets the code correctly' );
185 is( $letters->[0]->{name}, 'my name', 'GetLetters gets the name correctly' );
188 # getletter
189 subtest 'getletter' => sub {
190 plan tests => 16;
191 t::lib::Mocks::mock_preference('IndependentBranches', 0);
192 my $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
193 is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
194 is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
195 is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
196 is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
197 is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
198 is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
199 is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
200 is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
202 t::lib::Mocks::mock_userenv({ branchcode => "anotherlib", flags => 1 });
204 t::lib::Mocks::mock_preference('IndependentBranches', 1);
205 $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
206 is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
207 is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
208 is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
209 is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
210 is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
211 is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
212 is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
213 is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
218 # Regression test for Bug 14206
219 $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 );
220 my $letter14206_a = C4::Letters::getletter('my module', 'my code', 'FFL' );
221 is( $letter14206_a->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type not passed, correct mtt detected' );
222 my $letter14206_b = C4::Letters::getletter('my module', 'my code', 'FFL', 'print');
223 is( $letter14206_b->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type passed, correct mtt detected' );
225 # test for overdue_notices.pl
226 my $overdue_rules = {
227 letter1 => 'my code',
229 my $i = 1;
230 my $branchcode = 'FFL';
231 my $letter14206_c = C4::Letters::getletter('my module', $overdue_rules->{"letter$i"}, $branchcode);
232 is( $letter14206_c->{message_transport_type}, 'print', 'Bug 14206 - correct mtt detected for call from overdue_notices.pl' );
234 # GetPreparedLetter
235 t::lib::Mocks::mock_preference('OPACBaseURL', 'http://thisisatest.com');
237 my $sms_content = 'This is a SMS for an <<status>>';
238 $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 );
240 my $tables = {
241 borrowers => $borrowernumber,
242 branches => $library->{branchcode},
243 biblio => $biblionumber,
245 my $substitute = {
246 status => 'overdue',
248 my $repeat = [
250 itemcallnumber => 'my callnumber1',
251 barcode => '1234',
254 itemcallnumber => 'my callnumber2',
255 barcode => '5678',
258 my $prepared_letter = GetPreparedLetter((
259 module => 'my module',
260 branchcode => $library->{branchcode},
261 letter_code => 'my code',
262 tables => $tables,
263 substitute => $substitute,
264 repeat => $repeat,
266 my $retrieved_library = Koha::Libraries->find($library->{branchcode});
267 my $my_title_letter = $retrieved_library->branchname . qq| - $substitute->{status}|;
268 my $biblio_timestamp = dt_from_string( GetBiblioData($biblionumber)->{timestamp} );
269 my $my_content_letter = qq|Dear Jane Smith,
270 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.
272 |.$retrieved_library->branchname.qq|
273 |.$retrieved_library->branchaddress1.qq|
274 URL: http://thisisatest.com
276 The following item(s) is/are currently $substitute->{status}:
278 <item> 1. $repeat->[0]->{itemcallnumber}, Barcode: $repeat->[0]->{barcode} </item>
279 <item> 2. $repeat->[1]->{itemcallnumber}, Barcode: $repeat->[1]->{barcode} </item>
281 Thank-you for your prompt attention to this matter.
282 Don't forget your date of birth: | . output_pref({ dt => $date, dateonly => 1 }) . q|.
283 Look at this wonderful biblio timestamp: | . output_pref({ dt => $biblio_timestamp }) . ".\n";
285 is( $prepared_letter->{title}, $my_title_letter, 'GetPreparedLetter returns the title correctly' );
286 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
288 $prepared_letter = GetPreparedLetter((
289 module => 'my module',
290 branchcode => $library->{branchcode},
291 letter_code => 'my code',
292 tables => $tables,
293 substitute => $substitute,
294 repeat => $repeat,
295 message_transport_type => 'sms',
297 $my_content_letter = qq|This is a SMS for an $substitute->{status}|;
298 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
300 $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>>.');});
301 $prepared_letter = GetPreparedLetter((
302 module => 'test_date',
303 branchcode => '',
304 letter_code => 'test_date',
305 tables => $tables,
306 substitute => $substitute,
307 repeat => $repeat,
309 is( $prepared_letter->{content}, q|This one only contains the date: | . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 1' );
311 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp | dateonly>>.' WHERE code = 'test_date';});
312 $prepared_letter = GetPreparedLetter((
313 module => 'test_date',
314 branchcode => '',
315 letter_code => 'test_date',
316 tables => $tables,
317 substitute => $substitute,
318 repeat => $repeat,
320 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 2' );
322 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp|dateonly >>.' WHERE code = 'test_date';});
323 $prepared_letter = GetPreparedLetter((
324 module => 'test_date',
325 branchcode => '',
326 letter_code => 'test_date',
327 tables => $tables,
328 substitute => $substitute,
329 repeat => $repeat,
331 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 3' );
333 t::lib::Mocks::mock_preference( 'TimeFormat', '12hr' );
334 my $yesterday_night = $date->clone->add( days => -1 )->set_hour(22);
335 $dbh->do(q|UPDATE biblio SET timestamp = ? WHERE biblionumber = ?|, undef, $yesterday_night, $biblionumber );
336 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp>>.' WHERE code = 'test_date';});
337 $prepared_letter = GetPreparedLetter((
338 module => 'test_date',
339 branchcode => '',
340 letter_code => 'test_date',
341 tables => $tables,
342 substitute => $substitute,
343 repeat => $repeat,
345 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $yesterday_night }) . q|.|, 'dateonly test 3' );
347 $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>');});
348 $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>');});
350 # Test that _parseletter doesn't modify its parameters bug 15429
352 my $values = { dateexpiry => '2015-12-13', };
353 C4::Letters::_parseletter($prepared_letter, 'borrowers', $values);
354 is( $values->{dateexpiry}, '2015-12-13', "_parseletter doesn't modify its parameters" );
357 my $bookseller = Koha::Acquisition::Bookseller->new(
359 name => "my vendor",
360 address1 => "bookseller's address",
361 phone => "0123456",
362 active => 1,
363 deliverytime => 5,
365 )->store;
366 my $booksellerid = $bookseller->id;
368 Koha::Acquisition::Bookseller::Contact->new( { name => 'John Smith', phone => '0123456x1', claimacquisition => 1, orderacquisition => 1, booksellerid => $booksellerid } )->store;
369 Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues => 1, booksellerid => $booksellerid } )->store;
370 my $basketno = NewBasket($booksellerid, 1);
372 my $budgetid = C4::Budgets::AddBudget({
373 budget_code => "budget_code_test_letters",
374 budget_name => "budget_name_test_letters",
377 my $bib = MARC::Record->new();
378 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
379 $bib->append_fields(
380 MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
382 } else {
383 $bib->append_fields(
384 MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
388 my $logged_in_user = $builder->build_object({ class => 'Koha::Patrons', value => { branchcode => $library->{branchcode} }});
389 t::lib::Mocks::mock_userenv({ patron => $logged_in_user });
391 ($biblionumber, $biblioitemnumber) = AddBiblio($bib, '');
392 my $order = Koha::Acquisition::Order->new(
394 basketno => $basketno,
395 quantity => 1,
396 biblionumber => $biblionumber,
397 budget_id => $budgetid,
399 )->store;
400 my $ordernumber = $order->ordernumber;
402 C4::Acquisition::CloseBasket( $basketno );
403 my $err;
404 warning_like {
405 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
406 qr/^Bookseller .* without emails at/,
407 "SendAlerts prints a warning";
408 is($err->{'error'}, 'no_email', "Trying to send an alert when there's no e-mail results in an error");
410 $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
411 $bookseller->contacts->next->email('testemail@mydomain.com')->store;
413 # Ensure that the preference 'LetterLog' is set to logging
414 t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
416 # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
417 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
420 warning_is {
421 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
422 "Fake sendmail",
423 "SendAlerts is using the mocked sendmail routine (orderacquisition)";
424 is($err, 1, "Successfully sent order.");
425 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent order");
426 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Order notice text constructed successfully');
428 $dbh->do(q{DELETE FROM letter WHERE code = 'TESTACQORDER';});
429 warning_like {
430 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
431 qr/No orderacquisition TESTACQORDER letter transported by email/,
432 "GetPreparedLetter warns about missing notice template";
433 is($err->{'error'}, 'no_letter', "No TESTACQORDER letter was defined.");
437 warning_is {
438 $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
439 "Fake sendmail",
440 "SendAlerts is using the mocked sendmail routine";
442 is($err, 1, "Successfully sent claim");
443 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
444 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Claim notice text constructed successfully');
448 use C4::Serials;
450 my $notes = 'notes';
451 my $internalnotes = 'intnotes';
452 $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
453 my $subscriptionid = NewSubscription(
454 undef, "", undef, undef, undef, $biblionumber,
455 '2013-01-01', 1, undef, undef, undef,
456 undef, undef, undef, undef, undef, undef,
457 1, $notes,undef, '2013-01-01', undef, 1,
458 undef, undef, 0, $internalnotes, 0,
459 undef, undef, 0, undef, '2013-12-31', 0
461 $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>>');});
462 my ($serials_count, @serials) = GetSerials($subscriptionid);
463 my $serial = $serials[0];
465 my $patron = Koha::Patron->new({
466 firstname => 'John',
467 surname => 'Smith',
468 categorycode => $patron_category,
469 branchcode => $library->{branchcode},
470 dateofbirth => $date,
471 email => 'john.smith@test.de',
472 })->store;
473 my $borrowernumber = $patron->borrowernumber;
474 my $subscription = Koha::Subscriptions->find( $subscriptionid );
475 $subscription->add_subscriber( $patron );
477 my $err2;
478 warning_is {
479 $err2 = SendAlerts( 'issue', $serial->{serialid}, 'RLIST' ) }
480 "Fake sendmail",
481 "SendAlerts is using the mocked sendmail routine";
482 is($err2, 1, "Successfully sent serial notification");
483 is($mail{'To'}, 'john.smith@test.de', "mailto correct in sent serial notification");
484 is($mail{'Message'}, 'Silence in the library,'.$subscriptionid.',No. 0', 'Serial notification text constructed successfully');
487 subtest 'SendAlerts - claimissue' => sub {
488 plan tests => 8;
490 use C4::Serials;
492 $dbh->do(q{INSERT INTO letter (module, code, name, title, content) VALUES ('claimissues','TESTSERIALCLAIM','Serial claim test','Serial claim test','<<serial.serialid>>|<<subscription.startdate>>|<<biblio.title>>|<<biblioitems.issn>>');});
494 my $bookseller = Koha::Acquisition::Bookseller->new(
496 name => "my vendor",
497 address1 => "bookseller's address",
498 phone => "0123456",
499 active => 1,
500 deliverytime => 5,
502 )->store;
503 my $booksellerid = $bookseller->id;
505 Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues => 1, booksellerid => $booksellerid } )->store;
507 my $bib = MARC::Record->new();
508 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
509 $bib->append_fields(
510 MARC::Field->new('011', ' ', ' ', a => 'xxxx-yyyy'),
511 MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
513 } else {
514 $bib->append_fields(
515 MARC::Field->new('022', ' ', ' ', a => 'xxxx-yyyy'),
516 MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
519 my ($biblionumber) = AddBiblio($bib, '');
521 $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
522 my $subscriptionid = NewSubscription(
523 undef, "", $booksellerid, undef, undef, $biblionumber,
524 '2013-01-01', 1, undef, undef, undef,
525 undef, undef, undef, undef, undef, undef,
526 1, 'public',undef, '2013-01-01', undef, 1,
527 undef, undef, 0, 'internal', 0,
528 undef, undef, 0, undef, '2013-12-31', 0
531 my ($serials_count, @serials) = GetSerials($subscriptionid);
532 my @serialids = ($serials[0]->{serialid});
534 my $err;
535 warning_like {
536 $err = SendAlerts( 'claimissues', \@serialids, 'TESTSERIALCLAIM' ) }
537 qr/^Bookseller .* without emails at/,
538 "Warn on vendor without email address";
540 $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
541 $bookseller->contacts->next->email('testemail@mydomain.com')->store;
543 # Ensure that the preference 'LetterLog' is set to logging
544 t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
546 # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
547 t::lib::Mocks::mock_userenv({ branchcode => $library->{branchcode} });
549 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
552 warning_is {
553 $err = SendAlerts( 'claimissues', \@serialids , 'TESTSERIALCLAIM' ) }
554 "Fake sendmail",
555 "SendAlerts is using the mocked sendmail routine (claimissues)";
556 is($err, 1, "Successfully sent claim");
557 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
558 is($mail{'Message'}, "$serialids[0]|2013-01-01|Silence in the library|xxxx-yyyy", 'Serial claim letter for 1 issue constructed successfully');
562 my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
563 my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
564 ModSerialStatus( $serials[0]->{serialid}, "No. 1", $publisheddate, $publisheddate, $publisheddate, '3', 'a note' );
565 ($serials_count, @serials) = GetSerials($subscriptionid);
566 push @serialids, ($serials[1]->{serialid});
568 $err = SendAlerts( 'claimissues', \@serialids , 'TESTSERIALCLAIM' );
569 is($mail{'Message'}, "$serialids[0]|2013-01-01|Silence in the library|xxxx-yyyy\n$serialids[1]|2013-01-01|Silence in the library|xxxx-yyyy", "Serial claim letter for 2 issues constructed successfully");
571 $dbh->do(q{DELETE FROM letter WHERE code = 'TESTSERIALCLAIM';});
572 warning_like {
573 $err = SendAlerts( 'orderacquisition', $basketno , 'TESTSERIALCLAIM' ) }
574 qr/No orderacquisition TESTSERIALCLAIM letter transported by email/,
575 "GetPreparedLetter warns about missing notice template";
576 is($err->{'error'}, 'no_letter', "No TESTSERIALCLAIM letter was defined");
581 subtest 'GetPreparedLetter' => sub {
582 plan tests => 4;
584 Koha::Notice::Template->new(
586 module => 'test',
587 code => 'test',
588 branchcode => '',
589 message_transport_type => 'email'
591 )->store;
592 my $letter;
593 warning_like {
594 $letter = C4::Letters::GetPreparedLetter(
595 module => 'test',
596 letter_code => 'test',
599 qr{^ERROR: nothing to substitute},
600 'GetPreparedLetter should warn if tables, substiture and repeat are not set';
601 is( $letter, undef,
602 'No letter should be returned by GetPreparedLetter if something went wrong'
605 warning_like {
606 $letter = C4::Letters::GetPreparedLetter(
607 module => 'test',
608 letter_code => 'test',
609 substitute => {}
612 qr{^ERROR: nothing to substitute},
613 'GetPreparedLetter should warn if tables, substiture and repeat are not set, even if the key is passed';
614 is( $letter, undef,
615 'No letter should be returned by GetPreparedLetter if something went wrong'
622 subtest 'TranslateNotices' => sub {
623 plan tests => 4;
625 t::lib::Mocks::mock_preference( 'TranslateNotices', '1' );
627 $dbh->do(
629 INSERT INTO letter (module, code, branchcode, name, title, content, message_transport_type, lang) VALUES
630 ('test', 'code', '', 'test', 'a test', 'just a test', 'email', 'default'),
631 ('test', 'code', '', 'test', 'una prueba', 'solo una prueba', 'email', 'es-ES');
632 | );
633 my $substitute = {};
634 my $letter = C4::Letters::GetPreparedLetter(
635 module => 'test',
636 tables => $tables,
637 letter_code => 'code',
638 message_transport_type => 'email',
639 substitute => $substitute,
642 $letter->{title},
643 'a test',
644 'GetPreparedLetter should return the default one if the lang parameter is not provided'
647 $letter = C4::Letters::GetPreparedLetter(
648 module => 'test',
649 tables => $tables,
650 letter_code => 'code',
651 message_transport_type => 'email',
652 substitute => $substitute,
653 lang => 'es-ES',
655 is( $letter->{title}, 'una prueba',
656 'GetPreparedLetter should return the required notice if it exists' );
658 $letter = C4::Letters::GetPreparedLetter(
659 module => 'test',
660 tables => $tables,
661 letter_code => 'code',
662 message_transport_type => 'email',
663 substitute => $substitute,
664 lang => 'fr-FR',
667 $letter->{title},
668 'a test',
669 'GetPreparedLetter should return the default notice if the one required does not exist'
672 t::lib::Mocks::mock_preference( 'TranslateNotices', '' );
674 $letter = C4::Letters::GetPreparedLetter(
675 module => 'test',
676 tables => $tables,
677 letter_code => 'code',
678 message_transport_type => 'email',
679 substitute => $substitute,
680 lang => 'es-ES',
682 is( $letter->{title}, 'a test',
683 'GetPreparedLetter should return the default notice if pref disabled but additional language exists' );
687 subtest 'SendQueuedMessages' => sub {
689 plan tests => 6;
691 t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' );
692 t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', '');
694 my $patron = Koha::Patrons->find($borrowernumber);
695 $dbh->do(q|
696 INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code)
697 VALUES (?, 'subject', 'content', 'sms', 'pending', 'just_a_code')
698 |, undef, $borrowernumber
700 eval { C4::Letters::SendQueuedMessages(); };
701 is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
703 my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
704 $patron->set( { smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() } )->store;
705 $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
706 C4::Letters::SendQueuedMessages();
708 my $message = $schema->resultset('MessageQueue')->search({
709 borrowernumber => $borrowernumber,
710 status => 'sent'
711 })->next();
713 is( $message->to_address(), '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address not set' );
715 $message->from_address(),
716 'from@example.com',
717 'SendQueuedMessages uses message queue item \"from address\" for SMS by email when EmailSMSSendDriverFromAddress system preference is not set'
720 $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber, status => 'sent'})->delete(); #clear borrower queue
722 t::lib::Mocks::mock_preference('EmailSMSSendDriverFromAddress', 'override@example.com');
724 $message_id = C4::Letters::EnqueueLetter($my_message);
725 C4::Letters::SendQueuedMessages();
727 $message = $schema->resultset('MessageQueue')->search({
728 borrowernumber => $borrowernumber,
729 status => 'sent'
730 })->next();
733 $message->from_address(),
734 'override@example.com',
735 'SendQueuedMessages uses EmailSMSSendDriverFromAddress value for SMS by email when EmailSMSSendDriverFromAddress is set'
738 $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
739 $my_message->{to_address} = 'fixme@kidclamp.iswrong';
740 $message_id = C4::Letters::EnqueueLetter($my_message);
742 my $number_attempted = C4::Letters::SendQueuedMessages({
743 borrowernumber => -1, # -1 still triggers the borrowernumber condition
744 letter_code => 'PASSWORD_RESET',
746 is ( $number_attempted, 0, 'There were no password reset messages for SendQueuedMessages to attempt.' );
748 C4::Letters::SendQueuedMessages();
749 my $sms_message_address = $schema->resultset('MessageQueue')->search({
750 borrowernumber => $borrowernumber,
751 status => 'sent'
752 })->next()->to_address();
753 is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
757 subtest 'get_item_content' => sub {
758 plan tests => 2;
760 t::lib::Mocks::mock_preference('dateformat', 'metric');
761 t::lib::Mocks::mock_preference('timeformat', '24hr');
762 my @items = (
763 {date_due => '2041-01-01 12:34', title => 'a first title', barcode => 'a_first_barcode', author => 'a_first_author', itemnumber => 1 },
764 {date_due => '2042-01-02 23:45', title => 'a second title', barcode => 'a_second_barcode', author => 'a_second_author', itemnumber => 2 },
766 my @item_content_fields = qw( date_due title barcode author itemnumber );
768 my $items_content;
769 for my $item ( @items ) {
770 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields } );
773 my $expected_items_content = <<EOF;
774 01/01/2041 12:34\ta first title\ta_first_barcode\ta_first_author\t1
775 02/01/2042 23:45\ta second title\ta_second_barcode\ta_second_author\t2
777 is( $items_content, $expected_items_content, 'get_item_content should return correct items info with time (default)' );
780 $items_content = q||;
781 for my $item ( @items ) {
782 $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields, dateonly => 1, } );
785 $expected_items_content = <<EOF;
786 01/01/2041\ta first title\ta_first_barcode\ta_first_author\t1
787 02/01/2042\ta second title\ta_second_barcode\ta_second_author\t2
789 is( $items_content, $expected_items_content, 'get_item_content should return correct items info without time (if dateonly => 1)' );
792 subtest 'Test limit parameter for SendQueuedMessages' => sub {
793 plan tests => 3;
795 my $dbh = C4::Context->dbh;
797 my $borrowernumber = Koha::Patron->new({
798 firstname => 'Jane',
799 surname => 'Smith',
800 categorycode => $patron_category,
801 branchcode => $library->{branchcode},
802 dateofbirth => $date,
803 smsalertnumber => undef,
804 })->store->borrowernumber;
806 $dbh->do(q|DELETE FROM message_queue|);
807 $my_message = {
808 'letter' => {
809 'content' => 'a message',
810 'metadata' => 'metadata',
811 'code' => 'TEST_MESSAGE',
812 'content_type' => 'text/plain',
813 'title' => 'message title'
815 'borrowernumber' => $borrowernumber,
816 'to_address' => undef,
817 'message_transport_type' => 'sms',
818 'from_address' => 'from@example.com'
820 C4::Letters::EnqueueLetter($my_message);
821 C4::Letters::EnqueueLetter($my_message);
822 C4::Letters::EnqueueLetter($my_message);
823 C4::Letters::EnqueueLetter($my_message);
824 C4::Letters::EnqueueLetter($my_message);
825 my $messages_processed = C4::Letters::SendQueuedMessages( { limit => 1 } );
826 is( $messages_processed, 1,
827 'Processed 1 message with limit of 1 and 5 unprocessed messages' );
828 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 2 } );
829 is( $messages_processed, 2,
830 'Processed 2 message with limit of 2 and 4 unprocessed messages' );
831 $messages_processed = C4::Letters::SendQueuedMessages( { limit => 3 } );
832 is( $messages_processed, 2,
833 'Processed 2 message with limit of 3 and 2 unprocessed messages' );