Bug 22386: Remove debug statements
[koha.git] / t / db_dependent / Letters.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Copyright (C) 2013 Equinox Software, Inc.
6 #
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.
11 #
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.
16 #
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>.
19
20 use Modern::Perl;
21 use Test::More tests => 67;
22 use Test::MockModule;
23 use Test::Warn;
24
25 use MARC::Record;
26
27 my %mail;
28 my $module = new Test::MockModule('Mail::Sendmail');
29 $module->mock(
30     'sendmail',
31     sub {
32         warn "Fake sendmail";
33         %mail = @_;
34     }
35 );
36
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();
55
56 my $builder = t::lib::TestBuilder->new;
57 my $dbh = C4::Context->dbh;
58 $dbh->{RaiseError} = 1;
59
60 $dbh->do(q|DELETE FROM letter|);
61 $dbh->do(q|DELETE FROM message_queue|);
62 $dbh->do(q|DELETE FROM message_transport_types|);
63
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 = AddMember(
70     firstname    => 'Jane',
71     surname      => 'Smith',
72     categorycode => $patron_category,
73     branchcode   => $library->{branchcode},
74     dateofbirth  => $date,
75     smsalertnumber => undef,
76 );
77
78 my $marc_record = MARC::Record->new;
79 my( $biblionumber, $biblioitemnumber ) = AddBiblio( $marc_record, '' );
80
81
82
83 # GetMessageTransportTypes
84 my $mtts = C4::Letters::GetMessageTransportTypes();
85 is( @$mtts, 0, 'GetMessageTransportTypes returns the correct number of message types' );
86
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' );
92
93
94 # EnqueueLetter
95 is( C4::Letters::EnqueueLetter(), undef, 'EnqueueLetter without argument returns undef' );
96
97 my $my_message = {
98     borrowernumber         => $borrowernumber,
99     message_transport_type => 'sms',
100     to_address             => undef,
101     from_address           => 'from@example.com',
102 };
103 my $message_id = C4::Letters::EnqueueLetter($my_message);
104 is( $message_id, undef, 'EnqueueLetter without the letter argument returns undef' );
105
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',
113 };
114
115 $message_id = C4::Letters::EnqueueLetter($my_message);
116 is( $message_id, undef, 'EnqueueLetter without the message type argument argument returns undef' );
117
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');
121
122
123 # GetQueuedMessages
124 my $messages = C4::Letters::GetQueuedMessages();
125 is( @$messages, 1, 'GetQueuedMessages without argument returns all the entries' );
126
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' );
135
136
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 });
143 is(
144     $messages->[0]->{status},
145     'failed',
146     'message marked failed if tried to send SMS message for borrower with no smsalertnumber set (bug 11208)'
147 );
148
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' );
158
159 # GetLetters
160 my $letters = C4::Letters::GetLetters();
161 is( @$letters, 0, 'GetLetters returns the correct number of letters' );
162
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.
166
167 <<branches.branchname>>
168 <<branches.branchaddress1>>
169 URL: <<OPACBaseURL>>
170
171 The following item(s) is/are currently <<status>>:
172
173 <item> <<count>>. <<items.itemcallnumber>>, Barcode: <<items.barcode>> </item>
174
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>>.
178 };
179
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' );
186
187
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' );
201
202     my $context = Test::MockModule->new('C4::Context');
203     $context->mock( 'userenv', sub {
204         return {
205             flags  => 1,
206             branch => "anotherlib" }
207     });
208
209     t::lib::Mocks::mock_preference('IndependentBranches', 1);
210     $letter = C4::Letters::getletter('my module', 'my code', $library->{branchcode}, 'email');
211     is( $letter->{branchcode}, $library->{branchcode}, 'GetLetters gets the branch code correctly' );
212     is( $letter->{module}, 'my module', 'GetLetters gets the module correctly' );
213     is( $letter->{code}, 'my code', 'GetLetters gets the code correctly' );
214     is( $letter->{name}, 'my name', 'GetLetters gets the name correctly' );
215     is( $letter->{is_html}, 1, 'GetLetters gets the boolean is_html correctly' );
216     is( $letter->{title}, $title, 'GetLetters gets the title correctly' );
217     is( $letter->{content}, $content, 'GetLetters gets the content correctly' );
218     is( $letter->{message_transport_type}, 'email', 'GetLetters gets the message type correctly' );
219
220     $context->unmock('userenv');
221 };
222
223
224
225 # Regression test for Bug 14206
226 $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 );
227 my $letter14206_a = C4::Letters::getletter('my module', 'my code', 'FFL' );
228 is( $letter14206_a->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type not passed, correct mtt detected' );
229 my $letter14206_b = C4::Letters::getletter('my module', 'my code', 'FFL', 'print');
230 is( $letter14206_b->{message_transport_type}, 'print', 'Bug 14206 - message_transport_type passed, correct mtt detected'  );
231
232 # test for overdue_notices.pl
233 my $overdue_rules = {
234     letter1         => 'my code',
235 };
236 my $i = 1;
237 my $branchcode = 'FFL';
238 my $letter14206_c = C4::Letters::getletter('my module', $overdue_rules->{"letter$i"}, $branchcode);
239 is( $letter14206_c->{message_transport_type}, 'print', 'Bug 14206 - correct mtt detected for call from overdue_notices.pl' );
240
241 # GetPreparedLetter
242 t::lib::Mocks::mock_preference('OPACBaseURL', 'http://thisisatest.com');
243
244 my $sms_content = 'This is a SMS for an <<status>>';
245 $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 );
246
247 my $tables = {
248     borrowers => $borrowernumber,
249     branches => $library->{branchcode},
250     biblio => $biblionumber,
251 };
252 my $substitute = {
253     status => 'overdue',
254 };
255 my $repeat = [
256     {
257         itemcallnumber => 'my callnumber1',
258         barcode        => '1234',
259     },
260     {
261         itemcallnumber => 'my callnumber2',
262         barcode        => '5678',
263     },
264 ];
265 my $prepared_letter = GetPreparedLetter((
266     module      => 'my module',
267     branchcode  => $library->{branchcode},
268     letter_code => 'my code',
269     tables      => $tables,
270     substitute  => $substitute,
271     repeat      => $repeat,
272 ));
273 my $retrieved_library = Koha::Libraries->find($library->{branchcode});
274 my $my_title_letter = $retrieved_library->branchname . qq| - $substitute->{status}|;
275 my $biblio_timestamp = dt_from_string( GetBiblioData($biblionumber)->{timestamp} );
276 my $my_content_letter = qq|Dear Jane Smith,
277 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.
278
279 |.$retrieved_library->branchname.qq|
280 |.$retrieved_library->branchaddress1.qq|
281 URL: http://thisisatest.com
282
283 The following item(s) is/are currently $substitute->{status}:
284
285 <item> 1. $repeat->[0]->{itemcallnumber}, Barcode: $repeat->[0]->{barcode} </item>
286 <item> 2. $repeat->[1]->{itemcallnumber}, Barcode: $repeat->[1]->{barcode} </item>
287
288 Thank-you for your prompt attention to this matter.
289 Don't forget your date of birth: | . output_pref({ dt => $date, dateonly => 1 }) . q|.
290 Look at this wonderful biblio timestamp: | . output_pref({ dt => $biblio_timestamp })  . ".\n";
291
292 is( $prepared_letter->{title}, $my_title_letter, 'GetPreparedLetter returns the title correctly' );
293 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
294
295 $prepared_letter = GetPreparedLetter((
296     module                 => 'my module',
297     branchcode             => $library->{branchcode},
298     letter_code            => 'my code',
299     tables                 => $tables,
300     substitute             => $substitute,
301     repeat                 => $repeat,
302     message_transport_type => 'sms',
303 ));
304 $my_content_letter = qq|This is a SMS for an $substitute->{status}|;
305 is( $prepared_letter->{content}, $my_content_letter, 'GetPreparedLetter returns the content correctly' );
306
307 $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>>.');});
308 $prepared_letter = GetPreparedLetter((
309     module                 => 'test_date',
310     branchcode             => '',
311     letter_code            => 'test_date',
312     tables                 => $tables,
313     substitute             => $substitute,
314     repeat                 => $repeat,
315 ));
316 is( $prepared_letter->{content}, q|This one only contains the date: | . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 1' );
317
318 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp | dateonly>>.' WHERE code = 'test_date';});
319 $prepared_letter = GetPreparedLetter((
320     module                 => 'test_date',
321     branchcode             => '',
322     letter_code            => 'test_date',
323     tables                 => $tables,
324     substitute             => $substitute,
325     repeat                 => $repeat,
326 ));
327 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 2' );
328
329 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp|dateonly >>.' WHERE code = 'test_date';});
330 $prepared_letter = GetPreparedLetter((
331     module                 => 'test_date',
332     branchcode             => '',
333     letter_code            => 'test_date',
334     tables                 => $tables,
335     substitute             => $substitute,
336     repeat                 => $repeat,
337 ));
338 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $date, dateonly => 1 }) . q|.|, 'dateonly test 3' );
339
340 t::lib::Mocks::mock_preference( 'TimeFormat', '12hr' );
341 my $yesterday_night = $date->clone->add( days => -1 )->set_hour(22);
342 $dbh->do(q|UPDATE biblio SET timestamp = ? WHERE biblionumber = ?|, undef, $yesterday_night, $biblionumber );
343 $dbh->do(q{UPDATE letter SET content = 'And also this one:<<timestamp>>.' WHERE code = 'test_date';});
344 $prepared_letter = GetPreparedLetter((
345     module                 => 'test_date',
346     branchcode             => '',
347     letter_code            => 'test_date',
348     tables                 => $tables,
349     substitute             => $substitute,
350     repeat                 => $repeat,
351 ));
352 is( $prepared_letter->{content}, q|And also this one:| . output_pref({ dt => $yesterday_night }) . q|.|, 'dateonly test 3' );
353
354 $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>');});
355 $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>');});
356
357 # Test that _parseletter doesn't modify its parameters bug 15429
358 {
359     my $values = { dateexpiry => '2015-12-13', };
360     C4::Letters::_parseletter($prepared_letter, 'borrowers', $values);
361     is( $values->{dateexpiry}, '2015-12-13', "_parseletter doesn't modify its parameters" );
362 }
363
364 # Correctly format dateexpiry
365 {
366     my $values = { dateexpiry => '2015-12-13', };
367
368     t::lib::Mocks::mock_preference('dateformat', 'metric');
369     t::lib::Mocks::mock_preference('timeformat', '24hr');
370     my $letter = C4::Letters::_parseletter({ content => "expiry on <<borrowers.dateexpiry>>"}, 'borrowers', $values);
371     is( $letter->{content}, 'expiry on 13/12/2015' );
372
373     t::lib::Mocks::mock_preference('dateformat', 'metric');
374     t::lib::Mocks::mock_preference('timeformat', '12hr');
375     $letter = C4::Letters::_parseletter({ content => "expiry on <<borrowers.dateexpiry>>"}, 'borrowers', $values);
376     is( $letter->{content}, 'expiry on 13/12/2015' );
377 }
378
379 my $bookseller = Koha::Acquisition::Bookseller->new(
380     {
381         name => "my vendor",
382         address1 => "bookseller's address",
383         phone => "0123456",
384         active => 1,
385         deliverytime => 5,
386     }
387 )->store;
388 my $booksellerid = $bookseller->id;
389
390 Koha::Acquisition::Bookseller::Contact->new( { name => 'John Smith',  phone => '0123456x1', claimacquisition => 1, orderacquisition => 1, booksellerid => $booksellerid } )->store;
391 Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues      => 1, booksellerid => $booksellerid } )->store;
392 my $basketno = NewBasket($booksellerid, 1);
393
394 my $budgetid = C4::Budgets::AddBudget({
395     budget_code => "budget_code_test_letters",
396     budget_name => "budget_name_test_letters",
397 });
398
399 my $bib = MARC::Record->new();
400 if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
401     $bib->append_fields(
402         MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
403     );
404 } else {
405     $bib->append_fields(
406         MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
407     );
408 }
409
410 ($biblionumber, $biblioitemnumber) = AddBiblio($bib, '');
411 my $order = Koha::Acquisition::Order->new(
412     {
413         basketno => $basketno,
414         quantity => 1,
415         biblionumber => $biblionumber,
416         budget_id => $budgetid,
417     }
418 )->store;
419 my $ordernumber = $order->ordernumber;
420
421 C4::Acquisition::CloseBasket( $basketno );
422 my $err;
423 warning_like {
424     $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
425     qr/^Bookseller .* without emails at/,
426     "SendAlerts prints a warning";
427 is($err->{'error'}, 'no_email', "Trying to send an alert when there's no e-mail results in an error");
428
429 $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
430 $bookseller->contacts->next->email('testemail@mydomain.com')->store;
431
432 # Ensure that the preference 'LetterLog' is set to logging
433 t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
434
435 # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
436 C4::Context->_new_userenv('DUMMY');
437 C4::Context->set_userenv( 0, 0, 0, 'firstname', 'surname', $library->{branchcode}, 'My Library', 0, '', '');
438 t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
439
440 {
441 warning_is {
442     $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
443     "Fake sendmail",
444     "SendAlerts is using the mocked sendmail routine (orderacquisition)";
445 is($err, 1, "Successfully sent order.");
446 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent order");
447 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Order notice text constructed successfully');
448
449 $dbh->do(q{DELETE FROM letter WHERE code = 'TESTACQORDER';});
450 warning_like {
451     $err = SendAlerts( 'orderacquisition', $basketno , 'TESTACQORDER' ) }
452     qr/No orderacquisition TESTACQORDER letter transported by email/,
453     "GetPreparedLetter warns about missing notice template";
454 is($err->{'error'}, 'no_letter', "No TESTACQORDER letter was defined.");
455 }
456
457 {
458 warning_is {
459     $err = SendAlerts( 'claimacquisition', [ $ordernumber ], 'TESTACQCLAIM' ) }
460     "Fake sendmail",
461     "SendAlerts is using the mocked sendmail routine";
462
463 is($err, 1, "Successfully sent claim");
464 is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
465 is($mail{'Message'}, 'my vendor|John Smith|Ordernumber ' . $ordernumber . ' (Silence in the library) (1 ordered)', 'Claim notice text constructed successfully');
466 }
467
468 {
469 use C4::Serials;
470
471 my $notes = 'notes';
472 my $internalnotes = 'intnotes';
473 $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
474 my $subscriptionid = NewSubscription(
475      undef,      "",     undef, undef, undef, $biblionumber,
476     '2013-01-01', 1, undef, undef,  undef,
477     undef,      undef,  undef, undef, undef, undef,
478     1,          $notes,undef, '2013-01-01', undef, 1,
479     undef,       undef,  0,    $internalnotes,  0,
480     undef, undef, 0,          undef,         '2013-12-31', 0
481 );
482 $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>>');});
483 my ($serials_count, @serials) = GetSerials($subscriptionid);
484 my $serial = $serials[0];
485
486 my $borrowernumber = AddMember(
487     firstname    => 'John',
488     surname      => 'Smith',
489     categorycode => $patron_category,
490     branchcode   => $library->{branchcode},
491     dateofbirth  => $date,
492     email        => 'john.smith@test.de',
493 );
494 my $subscription = Koha::Subscriptions->find( $subscriptionid );
495 $subscription->add_subscriber( scalar Koha::Patrons->find( $borrowernumber ) );
496
497 my $err2;
498 warning_is {
499 $err2 = SendAlerts( 'issue', $serial->{serialid}, 'RLIST' ) }
500     "Fake sendmail",
501     "SendAlerts is using the mocked sendmail routine";
502 is($err2, 1, "Successfully sent serial notification");
503 is($mail{'To'}, 'john.smith@test.de', "mailto correct in sent serial notification");
504 is($mail{'Message'}, 'Silence in the library,'.$subscriptionid.',No. 0', 'Serial notification text constructed successfully');
505 }
506
507 subtest 'SendAlerts - claimissue' => sub {
508     plan tests => 8;
509
510     use C4::Serials;
511
512     $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>>');});
513
514     my $bookseller = Koha::Acquisition::Bookseller->new(
515         {
516             name => "my vendor",
517             address1 => "bookseller's address",
518             phone => "0123456",
519             active => 1,
520             deliverytime => 5,
521         }
522     )->store;
523     my $booksellerid = $bookseller->id;
524
525     Koha::Acquisition::Bookseller::Contact->new( { name => 'Leo Tolstoy', phone => '0123456x2', claimissues => 1, booksellerid => $booksellerid } )->store;
526
527     my $bib = MARC::Record->new();
528     if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
529         $bib->append_fields(
530             MARC::Field->new('011', ' ', ' ', a => 'xxxx-yyyy'),
531             MARC::Field->new('200', ' ', ' ', a => 'Silence in the library'),
532         );
533     } else {
534         $bib->append_fields(
535             MARC::Field->new('022', ' ', ' ', a => 'xxxx-yyyy'),
536             MARC::Field->new('245', ' ', ' ', a => 'Silence in the library'),
537         );
538     }
539     my ($biblionumber) = AddBiblio($bib, '');
540
541     $dbh->do(q|UPDATE subscription_numberpatterns SET numberingmethod='No. {X}' WHERE id=1|);
542     my $subscriptionid = NewSubscription(
543          undef, "", $booksellerid, undef, undef, $biblionumber,
544         '2013-01-01', 1, undef, undef,  undef,
545         undef,  undef,  undef, undef, undef, undef,
546         1, 'public',undef, '2013-01-01', undef, 1,
547         undef, undef,  0, 'internal',  0,
548         undef, undef, 0,  undef, '2013-12-31', 0
549     );
550
551     my ($serials_count, @serials) = GetSerials($subscriptionid);
552     my  @serialids = ($serials[0]->{serialid});
553
554     my $err;
555     warning_like {
556         $err = SendAlerts( 'claimissues', \@serialids, 'TESTSERIALCLAIM' ) }
557         qr/^Bookseller .* without emails at/,
558         "Warn on vendor without email address";
559
560     $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid );
561     $bookseller->contacts->next->email('testemail@mydomain.com')->store;
562
563     # Ensure that the preference 'LetterLog' is set to logging
564     t::lib::Mocks::mock_preference( 'LetterLog', 'on' );
565
566     # SendAlerts needs branchemail or KohaAdminEmailAddress as sender
567     C4::Context->_new_userenv('DUMMY');
568     C4::Context->set_userenv( 0, 0, 0, 'firstname', 'surname', $library->{branchcode}, 'My Library', 0, '', '');
569     t::lib::Mocks::mock_preference( 'KohaAdminEmailAddress', 'library@domain.com' );
570
571     {
572     warning_is {
573         $err = SendAlerts( 'claimissues', \@serialids , 'TESTSERIALCLAIM' ) }
574         "Fake sendmail",
575         "SendAlerts is using the mocked sendmail routine (claimissues)";
576     is($err, 1, "Successfully sent claim");
577     is($mail{'To'}, 'testemail@mydomain.com', "mailto correct in sent claim");
578     is($mail{'Message'}, "$serialids[0]|2013-01-01|Silence in the library|xxxx-yyyy", 'Serial claim letter for 1 issue constructed successfully');
579     }
580
581     {
582     my $publisheddate = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
583     my $serialexpected = ( C4::Serials::findSerialsByStatus( 1, $subscriptionid ) )[0];
584     ModSerialStatus( $serials[0]->{serialid}, "No. 1", $publisheddate, $publisheddate, $publisheddate, '3', 'a note' );
585     ($serials_count, @serials) = GetSerials($subscriptionid);
586     push @serialids, ($serials[1]->{serialid});
587
588     $err = SendAlerts( 'claimissues', \@serialids , 'TESTSERIALCLAIM' );
589     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");
590
591     $dbh->do(q{DELETE FROM letter WHERE code = 'TESTSERIALCLAIM';});
592     warning_like {
593         $err = SendAlerts( 'orderacquisition', $basketno , 'TESTSERIALCLAIM' ) }
594         qr/No orderacquisition TESTSERIALCLAIM letter transported by email/,
595         "GetPreparedLetter warns about missing notice template";
596     is($err->{'error'}, 'no_letter', "No TESTSERIALCLAIM letter was defined");
597     }
598
599 };
600
601 subtest 'GetPreparedLetter' => sub {
602     plan tests => 4;
603
604     Koha::Notice::Template->new(
605         {
606             module                 => 'test',
607             code                   => 'test',
608             branchcode             => '',
609             message_transport_type => 'email'
610         }
611     )->store;
612     my $letter;
613     warning_like {
614         $letter = C4::Letters::GetPreparedLetter(
615             module      => 'test',
616             letter_code => 'test',
617         );
618     }
619     qr{^ERROR: nothing to substitute},
620 'GetPreparedLetter should warn if tables, substiture and repeat are not set';
621     is( $letter, undef,
622 'No letter should be returned by GetPreparedLetter if something went wrong'
623     );
624
625     warning_like {
626         $letter = C4::Letters::GetPreparedLetter(
627             module      => 'test',
628             letter_code => 'test',
629             substitute  => {}
630         );
631     }
632     qr{^ERROR: nothing to substitute},
633 'GetPreparedLetter should warn if tables, substiture and repeat are not set, even if the key is passed';
634     is( $letter, undef,
635 'No letter should be returned by GetPreparedLetter if something went wrong'
636     );
637
638 };
639
640
641
642 subtest 'TranslateNotices' => sub {
643     plan tests => 4;
644
645     t::lib::Mocks::mock_preference( 'TranslateNotices', '1' );
646
647     $dbh->do(
648         q|
649         INSERT INTO letter (module, code, branchcode, name, title, content, message_transport_type, lang) VALUES
650         ('test', 'code', '', 'test', 'a test', 'just a test', 'email', 'default'),
651         ('test', 'code', '', 'test', 'una prueba', 'solo una prueba', 'email', 'es-ES');
652     | );
653     my $substitute = {};
654     my $letter = C4::Letters::GetPreparedLetter(
655             module                 => 'test',
656             tables                 => $tables,
657             letter_code            => 'code',
658             message_transport_type => 'email',
659             substitute             => $substitute,
660     );
661     is(
662         $letter->{title},
663         'a test',
664         'GetPreparedLetter should return the default one if the lang parameter is not provided'
665     );
666
667     $letter = C4::Letters::GetPreparedLetter(
668             module                 => 'test',
669             tables                 => $tables,
670             letter_code            => 'code',
671             message_transport_type => 'email',
672             substitute             => $substitute,
673             lang                   => 'es-ES',
674     );
675     is( $letter->{title}, 'una prueba',
676         'GetPreparedLetter should return the required notice if it exists' );
677
678     $letter = C4::Letters::GetPreparedLetter(
679             module                 => 'test',
680             tables                 => $tables,
681             letter_code            => 'code',
682             message_transport_type => 'email',
683             substitute             => $substitute,
684             lang                   => 'fr-FR',
685     );
686     is(
687         $letter->{title},
688         'a test',
689         'GetPreparedLetter should return the default notice if the one required does not exist'
690     );
691
692     t::lib::Mocks::mock_preference( 'TranslateNotices', '' );
693
694     $letter = C4::Letters::GetPreparedLetter(
695             module                 => 'test',
696             tables                 => $tables,
697             letter_code            => 'code',
698             message_transport_type => 'email',
699             substitute             => $substitute,
700             lang                   => 'es-ES',
701     );
702     is( $letter->{title}, 'a test',
703         'GetPreparedLetter should return the default notice if pref disabled but additional language exists' );
704
705 };
706
707 subtest 'SendQueuedMessages' => sub {
708
709     plan tests => 4;
710     t::lib::Mocks::mock_preference( 'SMSSendDriver', 'Email' );
711     my $patron = Koha::Patrons->find($borrowernumber);
712     $dbh->do(q|
713         INSERT INTO message_queue(borrowernumber, subject, content, message_transport_type, status, letter_code)
714         VALUES (?, 'subject', 'content', 'sms', 'pending', 'just_a_code')
715         |, undef, $borrowernumber
716     );
717     eval { C4::Letters::SendQueuedMessages(); };
718     is( $@, '', 'SendQueuedMessages should not explode if the patron does not have a sms provider set' );
719
720     my $sms_pro = $builder->build_object({ class => 'Koha::SMS::Providers', value => { domain => 'kidclamp.rocks' } });
721     ModMember( borrowernumber => $borrowernumber, smsalertnumber => '5555555555', sms_provider_id => $sms_pro->id() );
722     $message_id = C4::Letters::EnqueueLetter($my_message); #using datas set around line 95 and forward
723     C4::Letters::SendQueuedMessages();
724     my $sms_message_address = $schema->resultset('MessageQueue')->search({
725         borrowernumber => $borrowernumber,
726         status => 'sent'
727     })->next()->to_address();
728     is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address not set' );
729     $schema->resultset('MessageQueue')->search({borrowernumber => $borrowernumber,status => 'sent'})->delete(); #clear borrower queue
730     $my_message->{to_address} = 'fixme@kidclamp.iswrong';
731     $message_id = C4::Letters::EnqueueLetter($my_message);
732
733     my $number_attempted = C4::Letters::SendQueuedMessages({
734         borrowernumber => -1, # -1 still triggers the borrowernumber condition
735         letter_code    => 'PASSWORD_RESET',
736     });
737     is ( $number_attempted, 0, 'There were no password reset messages for SendQueuedMessages to attempt.' );
738
739     C4::Letters::SendQueuedMessages();
740     $sms_message_address = $schema->resultset('MessageQueue')->search({
741         borrowernumber => $borrowernumber,
742         status => 'sent'
743     })->next()->to_address();
744     is( $sms_message_address, '5555555555@kidclamp.rocks', 'SendQueuedMessages populates the to address correctly for SMS by email when to_address is set incorrectly' );
745
746 };
747
748 subtest 'get_item_content' => sub {
749     plan tests => 2;
750
751     t::lib::Mocks::mock_preference('dateformat', 'metric');
752     t::lib::Mocks::mock_preference('timeformat', '24hr');
753     my @items = (
754         {date_due => '2041-01-01 12:34', title => 'a first title', barcode => 'a_first_barcode', author => 'a_first_author', itemnumber => 1 },
755         {date_due => '2042-01-02 23:45', title => 'a second title', barcode => 'a_second_barcode', author => 'a_second_author', itemnumber => 2 },
756     );
757     my @item_content_fields = qw( date_due title barcode author itemnumber );
758
759     my $items_content;
760     for my $item ( @items ) {
761         $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields } );
762     }
763
764     my $expected_items_content = <<EOF;
765 01/01/2041 12:34\ta first title\ta_first_barcode\ta_first_author\t1
766 02/01/2042 23:45\ta second title\ta_second_barcode\ta_second_author\t2
767 EOF
768     is( $items_content, $expected_items_content, 'get_item_content should return correct items info with time (default)' );
769
770
771     $items_content = q||;
772     for my $item ( @items ) {
773         $items_content .= C4::Letters::get_item_content( { item => $item, item_content_fields => \@item_content_fields, dateonly => 1, } );
774     }
775
776     $expected_items_content = <<EOF;
777 01/01/2041\ta first title\ta_first_barcode\ta_first_author\t1
778 02/01/2042\ta second title\ta_second_barcode\ta_second_author\t2
779 EOF
780     is( $items_content, $expected_items_content, 'get_item_content should return correct items info without time (if dateonly => 1)' );
781 };
782
783 subtest 'Test limit parameter for SendQueuedMessages' => sub {
784     plan tests => 3;
785
786     my $dbh = C4::Context->dbh;
787
788     my $borrowernumber = AddMember(
789         firstname    => 'Jane',
790         surname      => 'Smith',
791         categorycode => $patron_category,
792         branchcode   => $library->{branchcode},
793         dateofbirth  => $date,
794         smsalertnumber => undef,
795     );
796
797     $dbh->do(q|DELETE FROM message_queue|);
798     $my_message = {
799         'letter' => {
800             'content'      => 'a message',
801             'metadata'     => 'metadata',
802             'code'         => 'TEST_MESSAGE',
803             'content_type' => 'text/plain',
804             'title'        => 'message title'
805         },
806         'borrowernumber'         => $borrowernumber,
807         'to_address'             => undef,
808         'message_transport_type' => 'sms',
809         'from_address'           => 'from@example.com'
810     };
811     C4::Letters::EnqueueLetter($my_message);
812     C4::Letters::EnqueueLetter($my_message);
813     C4::Letters::EnqueueLetter($my_message);
814     C4::Letters::EnqueueLetter($my_message);
815     C4::Letters::EnqueueLetter($my_message);
816     my $messages_processed = C4::Letters::SendQueuedMessages( { limit => 1 } );
817     is( $messages_processed, 1,
818         'Processed 1 message with limit of 1 and 5 unprocessed messages' );
819     $messages_processed = C4::Letters::SendQueuedMessages( { limit => 2 } );
820     is( $messages_processed, 2,
821         'Processed 2 message with limit of 2 and 4 unprocessed messages' );
822     $messages_processed = C4::Letters::SendQueuedMessages( { limit => 3 } );
823     is( $messages_processed, 2,
824         'Processed 2 message with limit of 3 and 2 unprocessed messages' );
825 };