Merge pull request #6746 from systopia/CRM-17218
[civicrm-core.git] / tests / phpunit / CRM / Core / BAO / ActionScheduleTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28
29 require_once 'CiviTest/CiviUnitTestCase.php';
30
31 /**
32 * Class CRM_Core_BAO_ActionScheduleTest
33 */
34 class CRM_Core_BAO_ActionScheduleTest extends CiviUnitTestCase {
35
36 /**
37 * @var CiviMailUtils
38 */
39 public $mut;
40
41 public function setUp() {
42 parent::setUp();
43
44 require_once 'CiviTest/CiviMailUtils.php';
45 $this->mut = new CiviMailUtils($this, TRUE);
46
47 $this->fixtures['rolling_membership'] = array(
48 'membership_type_id' => array(
49 'period_type' => 'rolling',
50 'duration_unit' => 'month',
51 'duration_interval' => '3',
52 'is_active' => 1,
53 ),
54 'join_date' => '20120315',
55 'start_date' => '20120315',
56 'end_date' => '20120615',
57 'is_override' => 0,
58 );
59
60 $this->fixtures['rolling_membership_past'] = array(
61 'membership_type_id' => array(
62 'period_type' => 'rolling',
63 'duration_unit' => 'month',
64 'duration_interval' => '3',
65 'is_active' => 1,
66 ),
67 'join_date' => '20100310',
68 'start_date' => '20100310',
69 'end_date' => '20100610',
70 'is_override' => 'NULL',
71 );
72 $this->fixtures['participant'] = array(
73 'event_id' => array(
74 'is_active' => 1,
75 'is_template' => 0,
76 'title' => 'Example Event',
77 'start_date' => '20120315',
78 'end_date' => '20120615',
79 ),
80 'role_id' => '1', // Attendee.
81 'status_id' => '8', // No-show.
82 );
83
84 $this->fixtures['phonecall'] = array(
85 'status_id' => 1,
86 'activity_type_id' => 2,
87 'activity_date_time' => '20120615100000',
88 'is_current_revision' => 1,
89 'is_deleted' => 0,
90 );
91 $this->fixtures['contact'] = array(
92 'is_deceased' => 0,
93 'contact_type' => 'Individual',
94 'email' => 'test-member@example.com',
95 'gender_id' => 'Female',
96 );
97 $this->fixtures['contact_birthdate'] = array(
98 'is_deceased' => 0,
99 'contact_type' => 'Individual',
100 'email' => 'test-bday@example.com',
101 'birth_date' => '20050707',
102 );
103 $this->fixtures['sched_activity_1day'] = array(
104 'name' => 'One_Day_Phone_Call_Notice',
105 'title' => 'One Day Phone Call Notice',
106 'limit_to' => '1',
107 'absolute_date' => NULL,
108 'body_html' => '<p>1-Day (non-repeating)</p>',
109 'body_text' => '1-Day (non-repeating)',
110 'end_action' => NULL,
111 'end_date' => NULL,
112 'end_frequency_interval' => NULL,
113 'end_frequency_unit' => NULL,
114 'entity_status' => '1',
115 'entity_value' => '2',
116 'group_id' => NULL,
117 'is_active' => '1',
118 'is_repeat' => '0',
119 'mapping_id' => '1',
120 'msg_template_id' => NULL,
121 'recipient' => '2',
122 'recipient_listing' => NULL,
123 'recipient_manual' => NULL,
124 'record_activity' => NULL,
125 'repetition_frequency_interval' => NULL,
126 'repetition_frequency_unit' => NULL,
127 'start_action_condition' => 'before',
128 'start_action_date' => 'activity_date_time',
129 'start_action_offset' => '1',
130 'start_action_unit' => 'day',
131 'subject' => '1-Day (non-repeating) (about {activity.activity_type})',
132 );
133 $this->fixtures['sched_activity_1day_r'] = array(
134 'name' => 'One_Day_Phone_Call_Notice_R',
135 'title' => 'One Day Phone Call Notice R',
136 'limit_to' => 1,
137 'absolute_date' => NULL,
138 'body_html' => '<p>1-Day (repeating)</p>',
139 'body_text' => '1-Day (repeating)',
140 'end_action' => 'after',
141 'end_date' => 'activity_date_time',
142 'end_frequency_interval' => '2',
143 'end_frequency_unit' => 'day',
144 'entity_status' => '1',
145 'entity_value' => '2',
146 'group_id' => NULL,
147 'is_active' => '1',
148 'is_repeat' => '1',
149 'mapping_id' => '1',
150 'msg_template_id' => NULL,
151 'recipient' => '2',
152 'recipient_listing' => NULL,
153 'recipient_manual' => NULL,
154 'record_activity' => NULL,
155 'repetition_frequency_interval' => '6',
156 'repetition_frequency_unit' => 'hour',
157 'start_action_condition' => 'before',
158 'start_action_date' => 'activity_date_time',
159 'start_action_offset' => '1',
160 'start_action_unit' => 'day',
161 'subject' => '1-Day (repeating) (about {activity.activity_type})',
162 );
163 $this->fixtures['sched_membership_join_2week'] = array(
164 'name' => 'sched_membership_join_2week',
165 'title' => 'sched_membership_join_2week',
166 'absolute_date' => '',
167 'body_html' => '<p>body sched_membership_join_2week</p>',
168 'body_text' => 'body sched_membership_join_2week',
169 'end_action' => '',
170 'end_date' => '',
171 'end_frequency_interval' => '',
172 'end_frequency_unit' => '',
173 'entity_status' => '',
174 'entity_value' => '',
175 'group_id' => '',
176 'is_active' => 1,
177 'is_repeat' => '0',
178 'mapping_id' => 4,
179 'msg_template_id' => '',
180 'recipient' => '',
181 'recipient_listing' => '',
182 'recipient_manual' => '',
183 'record_activity' => 1,
184 'repetition_frequency_interval' => '',
185 'repetition_frequency_unit' => '',
186 'start_action_condition' => 'after',
187 'start_action_date' => 'membership_join_date',
188 'start_action_offset' => '2',
189 'start_action_unit' => 'week',
190 'subject' => 'subject sched_membership_join_2week (joined {membership.join_date})',
191 );
192 $this->fixtures['sched_membership_end_2week'] = array(
193 'name' => 'sched_membership_end_2week',
194 'title' => 'sched_membership_end_2week',
195 'absolute_date' => '',
196 'body_html' => '<p>body sched_membership_end_2week</p>',
197 'body_text' => 'body sched_membership_end_2week',
198 'end_action' => '',
199 'end_date' => '',
200 'end_frequency_interval' => '',
201 'end_frequency_unit' => '',
202 'entity_status' => '',
203 'entity_value' => '',
204 'group_id' => '',
205 'is_active' => 1,
206 'is_repeat' => '0',
207 'mapping_id' => 4,
208 'msg_template_id' => '',
209 'recipient' => '',
210 'recipient_listing' => '',
211 'recipient_manual' => '',
212 'record_activity' => 1,
213 'repetition_frequency_interval' => '',
214 'repetition_frequency_unit' => '',
215 'start_action_condition' => 'before',
216 'start_action_date' => 'membership_end_date',
217 'start_action_offset' => '2',
218 'start_action_unit' => 'week',
219 'subject' => 'subject sched_membership_end_2week',
220 );
221 $this->fixtures['sched_on_membership_end_date'] = array(
222 'name' => 'sched_on_membership_end_date',
223 'title' => 'sched_on_membership_end_date',
224 'body_html' => '<p>Your membership expired today</p>',
225 'body_text' => 'Your membership expired today',
226 'is_active' => 1,
227 'mapping_id' => 4,
228 'record_activity' => 1,
229 'start_action_condition' => 'after',
230 'start_action_date' => 'membership_end_date',
231 'start_action_offset' => '0',
232 'start_action_unit' => 'hour',
233 'subject' => 'subject send reminder on membership_end_date',
234 );
235 $this->fixtures['sched_after_1day_membership_end_date'] = array(
236 'name' => 'sched_after_1day_membership_end_date',
237 'title' => 'sched_after_1day_membership_end_date',
238 'body_html' => '<p>Your membership expired yesterday</p>',
239 'body_text' => 'Your membership expired yesterday',
240 'is_active' => 1,
241 'mapping_id' => 4,
242 'record_activity' => 1,
243 'start_action_condition' => 'after',
244 'start_action_date' => 'membership_end_date',
245 'start_action_offset' => '1',
246 'start_action_unit' => 'day',
247 'subject' => 'subject send reminder on membership_end_date',
248 );
249
250 $this->fixtures['sched_membership_end_2month'] = array(
251 'name' => 'sched_membership_end_2month',
252 'title' => 'sched_membership_end_2month',
253 'absolute_date' => '',
254 'body_html' => '<p>body sched_membership_end_2month</p>',
255 'body_text' => 'body sched_membership_end_2month',
256 'end_action' => '',
257 'end_date' => '',
258 'end_frequency_interval' => '',
259 'end_frequency_unit' => '',
260 'entity_status' => '',
261 'entity_value' => '',
262 'group_id' => '',
263 'is_active' => 1,
264 'is_repeat' => '0',
265 'mapping_id' => 4,
266 'msg_template_id' => '',
267 'recipient' => '',
268 'recipient_listing' => '',
269 'recipient_manual' => '',
270 'record_activity' => 1,
271 'repetition_frequency_interval' => '',
272 'repetition_frequency_unit' => '',
273 'start_action_condition' => 'after',
274 'start_action_date' => 'membership_end_date',
275 'start_action_offset' => '2',
276 'start_action_unit' => 'month',
277 'subject' => 'subject sched_membership_end_2month',
278 );
279
280 $this->fixtures['sched_contact_bday_yesterday'] = array(
281 'name' => 'sched_contact_bday_yesterday',
282 'title' => 'sched_contact_bday_yesterday',
283 'absolute_date' => '',
284 'body_html' => '<p>you look like you were born yesterday!</p>',
285 'body_text' => 'you look like you were born yesterday!',
286 'end_action' => '',
287 'end_date' => '',
288 'end_frequency_interval' => '',
289 'end_frequency_unit' => '',
290 'entity_status' => 1,
291 'entity_value' => 'birth_date',
292 'group_id' => '',
293 'is_active' => 1,
294 'is_repeat' => '0',
295 'mapping_id' => 6,
296 'msg_template_id' => '',
297 'recipient' => '',
298 'recipient_listing' => '',
299 'recipient_manual' => '',
300 'record_activity' => 1,
301 'repetition_frequency_interval' => '',
302 'repetition_frequency_unit' => '',
303 'start_action_condition' => 'after',
304 'start_action_date' => 'date_field',
305 'start_action_offset' => '1',
306 'start_action_unit' => 'day',
307 'subject' => 'subject sched_contact_bday_yesterday',
308 );
309
310 $this->fixtures['sched_contact_bday_anniv'] = array(
311 'name' => 'sched_contact_bday_anniv',
312 'title' => 'sched_contact_bday_anniv',
313 'absolute_date' => '',
314 'body_html' => '<p>happy birthday!</p>',
315 'body_text' => 'happy birthday!',
316 'end_action' => '',
317 'end_date' => '',
318 'end_frequency_interval' => '',
319 'end_frequency_unit' => '',
320 'entity_status' => 2,
321 'entity_value' => 'birth_date',
322 'group_id' => '',
323 'is_active' => 1,
324 'is_repeat' => '0',
325 'mapping_id' => 6,
326 'msg_template_id' => '',
327 'recipient' => '',
328 'recipient_listing' => '',
329 'recipient_manual' => '',
330 'record_activity' => 1,
331 'repetition_frequency_interval' => '',
332 'repetition_frequency_unit' => '',
333 'start_action_condition' => 'before',
334 'start_action_date' => 'date_field',
335 'start_action_offset' => '1',
336 'start_action_unit' => 'day',
337 'subject' => 'subject sched_contact_bday_anniv',
338 );
339
340 $this->fixtures['sched_contact_grad_tomorrow'] = array(
341 'name' => 'sched_contact_grad_tomorrow',
342 'title' => 'sched_contact_grad_tomorrow',
343 'absolute_date' => '',
344 'body_html' => '<p>congratulations on your graduation!</p>',
345 'body_text' => 'congratulations on your graduation!',
346 'end_action' => '',
347 'end_date' => '',
348 'end_frequency_interval' => '',
349 'end_frequency_unit' => '',
350 'entity_status' => 1,
351 'group_id' => '',
352 'is_active' => 1,
353 'is_repeat' => '0',
354 'mapping_id' => 6,
355 'msg_template_id' => '',
356 'recipient' => '',
357 'recipient_listing' => '',
358 'recipient_manual' => '',
359 'record_activity' => 1,
360 'repetition_frequency_interval' => '',
361 'repetition_frequency_unit' => '',
362 'start_action_condition' => 'before',
363 'start_action_date' => 'date_field',
364 'start_action_offset' => '1',
365 'start_action_unit' => 'day',
366 'subject' => 'subject sched_contact_grad_tomorrow',
367 );
368
369 $this->fixtures['sched_contact_grad_anniv'] = array(
370 'name' => 'sched_contact_grad_anniv',
371 'title' => 'sched_contact_grad_anniv',
372 'absolute_date' => '',
373 'body_html' => '<p>dear alum, please send us money.</p>',
374 'body_text' => 'dear alum, please send us money.',
375 'end_action' => '',
376 'end_date' => '',
377 'end_frequency_interval' => '',
378 'end_frequency_unit' => '',
379 'entity_status' => 2,
380 'group_id' => '',
381 'is_active' => 1,
382 'is_repeat' => '0',
383 'mapping_id' => 6,
384 'msg_template_id' => '',
385 'recipient' => '',
386 'recipient_listing' => '',
387 'recipient_manual' => '',
388 'record_activity' => 1,
389 'repetition_frequency_interval' => '',
390 'repetition_frequency_unit' => '',
391 'start_action_condition' => 'after',
392 'start_action_date' => 'date_field',
393 'start_action_offset' => '1',
394 'start_action_unit' => 'week',
395 'subject' => 'subject sched_contact_grad_anniv',
396 );
397
398 $this->fixtures['sched_contact_created_yesterday'] = array(
399 'name' => 'sched_contact_created_yesterday',
400 'title' => 'sched_contact_created_yesterday',
401 'absolute_date' => '',
402 'body_html' => '<p>Your contact was created yesterday</p>',
403 'body_text' => 'Your contact was created yesterday!',
404 'end_action' => '',
405 'end_date' => '',
406 'end_frequency_interval' => '',
407 'end_frequency_unit' => '',
408 'entity_status' => 1,
409 'entity_value' => 'created_date',
410 'group_id' => '',
411 'is_active' => 1,
412 'is_repeat' => '0',
413 'mapping_id' => 6,
414 'msg_template_id' => '',
415 'recipient' => '',
416 'recipient_listing' => '',
417 'recipient_manual' => '',
418 'record_activity' => 1,
419 'repetition_frequency_interval' => '',
420 'repetition_frequency_unit' => '',
421 'start_action_condition' => 'after',
422 'start_action_date' => 'date_field',
423 'start_action_offset' => '1',
424 'start_action_unit' => 'day',
425 'subject' => 'subject sched_contact_created_yesterday',
426 );
427
428 $this->fixtures['sched_contact_mod_anniv'] = array(
429 'name' => 'sched_contact_mod_anniv',
430 'title' => 'sched_contact_mod_anniv',
431 'absolute_date' => '',
432 'body_html' => '<p>You last updated your data last year</p>',
433 'body_text' => 'Go update your stuff!',
434 'end_action' => '',
435 'end_date' => '',
436 'end_frequency_interval' => '',
437 'end_frequency_unit' => '',
438 'entity_status' => 2,
439 'entity_value' => 'modified_date',
440 'group_id' => '',
441 'is_active' => 1,
442 'is_repeat' => '0',
443 'mapping_id' => 6,
444 'msg_template_id' => '',
445 'recipient' => '',
446 'recipient_listing' => '',
447 'recipient_manual' => '',
448 'record_activity' => 1,
449 'repetition_frequency_interval' => '',
450 'repetition_frequency_unit' => '',
451 'start_action_condition' => 'before',
452 'start_action_date' => 'date_field',
453 'start_action_offset' => '1',
454 'start_action_unit' => 'day',
455 'subject' => 'subject sched_contact_mod_anniv',
456 );
457
458 $this->fixtures['sched_eventtype_start_1week_before'] = array(
459 'name' => 'sched_eventtype_start_1week_before',
460 'title' => 'sched_eventtype_start_1week_before',
461 'absolute_date' => '',
462 'body_html' => '<p>body sched_eventtype_start_1week_before ({event.title})</p>',
463 'body_text' => 'body sched_eventtype_start_1week_before ({event.title})',
464 'end_action' => '',
465 'end_date' => '',
466 'end_frequency_interval' => '',
467 'end_frequency_unit' => '',
468 'entity_status' => '', // participant status id
469 'entity_value' => '', // event type id
470 'group_id' => '',
471 'is_active' => 1,
472 'is_repeat' => '0',
473 'mapping_id' => 2, // event type
474 'msg_template_id' => '',
475 'recipient' => '',
476 'recipient_listing' => '',
477 'recipient_manual' => '',
478 'record_activity' => 1,
479 'repetition_frequency_interval' => '',
480 'repetition_frequency_unit' => '',
481 'start_action_condition' => 'before',
482 'start_action_date' => 'event_start_date',
483 'start_action_offset' => '1',
484 'start_action_unit' => 'week',
485 'subject' => 'subject sched_eventtype_start_1week_before ({event.title})',
486 );
487 $this->fixtures['sched_eventtype_end_2month_repeat_twice_2_weeks'] = array(
488 'name' => 'sched_eventtype_end_2month_repeat_twice_2_weeks',
489 'title' => 'sched_eventtype_end_2month_repeat_twice_2_weeks',
490 'absolute_date' => '',
491 'body_html' => '<p>body sched_eventtype_end_2month_repeat_twice_2_weeks {event.title}</p>',
492 'body_text' => 'body sched_eventtype_end_2month_repeat_twice_2_weeks {event.title}',
493 'end_action' => 'after',
494 'end_date' => 'event_end_date',
495 'end_frequency_interval' => '3',
496 'end_frequency_unit' => 'month',
497 'entity_status' => '', // participant status id
498 'entity_value' => '', // event type id
499 'group_id' => '',
500 'is_active' => 1,
501 'is_repeat' => '1',
502 'mapping_id' => 2, // event type
503 'msg_template_id' => '',
504 'recipient' => '',
505 'recipient_listing' => '',
506 'recipient_manual' => '',
507 'record_activity' => 1,
508 'repetition_frequency_interval' => '2',
509 'repetition_frequency_unit' => 'week',
510 'start_action_condition' => 'after',
511 'start_action_date' => 'event_end_date',
512 'start_action_offset' => '2',
513 'start_action_unit' => 'month',
514 'subject' => 'subject sched_eventtype_end_2month_repeat_twice_2_weeks {event.title}',
515 );
516
517 $this->fixtures['sched_membership_end_2month_repeat_twice_4_weeks'] = array(
518 'name' => 'sched_membership_end_2month',
519 'title' => 'sched_membership_end_2month',
520 'absolute_date' => '',
521 'body_html' => '<p>body sched_membership_end_2month</p>',
522 'body_text' => 'body sched_membership_end_2month',
523 'end_action' => '',
524 'end_date' => 'membership_end_date',
525 'end_frequency_interval' => '4',
526 'end_frequency_unit' => 'month',
527 'entity_status' => '',
528 'entity_value' => '',
529 'group_id' => '',
530 'is_active' => 1,
531 'is_repeat' => '1',
532 'mapping_id' => 4,
533 'msg_template_id' => '',
534 'recipient' => '',
535 'recipient_listing' => '',
536 'recipient_manual' => '',
537 'record_activity' => 1,
538 'repetition_frequency_interval' => '4',
539 'repetition_frequency_unit' => 'week',
540 'start_action_condition' => 'after',
541 'start_action_date' => 'membership_end_date',
542 'start_action_offset' => '2',
543 'start_action_unit' => 'month',
544 'subject' => 'subject sched_membership_end_2month',
545 );
546 $this->fixtures['sched_membership_end_limit_to_none'] = array(
547 'name' => 'limit to none',
548 'title' => 'limit to none',
549 'absolute_date' => '',
550 'body_html' => '<p>body sched_membership_end_2month</p>',
551 'body_text' => 'body sched_membership_end_2month',
552 'end_action' => '',
553 'end_date' => '',
554 'end_frequency_interval' => '4',
555 'end_frequency_unit' => 'month',
556 'entity_status' => '',
557 'entity_value' => '',
558 'limit_to' => 0,
559 'group_id' => '',
560 'is_active' => 1,
561 'is_repeat' => '1',
562 'mapping_id' => 4,
563 'msg_template_id' => '',
564 'recipient' => '',
565 'recipient_listing' => '',
566 'recipient_manual' => '',
567 'record_activity' => 1,
568 'repetition_frequency_interval' => '4',
569 'repetition_frequency_unit' => 'week',
570 'start_action_condition' => 'after',
571 'start_action_date' => 'membership_end_date',
572 'start_action_offset' => '2',
573 'start_action_unit' => 'month',
574 'subject' => 'limit to none',
575 );
576 $this->_setUp();
577 }
578
579 /**
580 * Tears down the fixture, for example, closes a network connection.
581 *
582 * This method is called after a test is executed.
583 */
584 public function tearDown() {
585 parent::tearDown();
586
587 $this->mut->clearMessages();
588 $this->mut->stop();
589 unset($this->mut);
590 $this->quickCleanup(array(
591 'civicrm_action_schedule',
592 'civicrm_action_log',
593 'civicrm_membership',
594 'civicrm_participant',
595 'civicrm_event',
596 'civicrm_email',
597 ));
598 $this->_tearDown();
599 }
600
601 public function mailerExamples() {
602 $cases = array();
603
604 $manyTokensTmpl = implode(';;', array(
605 '{contact.display_name}', // basic contact token
606 '{contact.gender}', // funny legacy contact token
607 '{contact.gender_id}', // funny legacy contact token
608 '{domain.name}', // domain token
609 '{activity.activity_type}', // action-scheduler token
610 ));
611 // Note: The behavior of domain-tokens on a scheduled reminder is undefined. All we
612 // can really do is check that it has something.
613 $manyTokensExpected = 'test-member@example.com;;Female;;Female;;[a-zA-Z0-9 ]+;;Phone Call';
614
615 // In this example, we use a lot of tokens cutting across multiple components..
616 $cases[0] = array(
617 // Schedule definition.
618 array(
619 'subject' => "subj $manyTokensTmpl",
620 'body_html' => "html $manyTokensTmpl",
621 'body_text' => "text $manyTokensTmpl",
622 ),
623 // Assertions (regex).
624 array(
625 'from_name' => "/^FIXME\$/",
626 'from_email' => "/^info@EXAMPLE.ORG\$/",
627 'subject' => "/^subj $manyTokensExpected\$/",
628 'body_html' => "/^html $manyTokensExpected\$/",
629 'body_text' => "/^text $manyTokensExpected\$/",
630 ),
631 );
632
633 // In this example, we customize the from address.
634 $cases[1] = array(
635 // Schedule definition.
636 array(
637 'from_name' => 'Bob',
638 'from_email' => 'bob@example.org',
639 ),
640 // Assertions (regex).
641 array(
642 'from_name' => "/^Bob\$/",
643 'from_email' => "/^bob@example.org\$/",
644 ),
645 );
646
647 // In this example, we autoconvert HTML to text
648 $cases[2] = array(
649 // Schedule definition.
650 array(
651 'body_html' => '<p>Hello &amp; stuff.</p>',
652 'body_text' => '',
653 ),
654 // Assertions (regex).
655 array(
656 'body_html' => '/^' . preg_quote('<p>Hello &amp; stuff.</p>', '/') . '/',
657 'body_text' => '/^' . preg_quote('Hello & stuff.', '/') . '/',
658 ),
659 );
660
661 // In this example, we autoconvert HTML to text
662 $cases[3] = array(
663 // Schedule definition.
664 array(
665 'body_html' => '',
666 'body_text' => 'Hello world',
667 ),
668 // Assertions (regex).
669 array(
670 'body_html' => '/^--UNDEFINED--$/',
671 'body_text' => '/^Hello world$/',
672 ),
673 );
674
675 return $cases;
676 }
677
678 /**
679 * This generates a single mailing through the scheduled-reminder
680 * system (using an activity-reminder as a baseline) and
681 * checks that the resulting message satisfies various
682 * regular expressions.
683 *
684 * @param array $schedule
685 * Values to set/override in the schedule.
686 * Ex: array('subject' => 'Hello, {contact.first_name}!').
687 * @param array $patterns
688 * A list of regexes to compare with the actual email.
689 * Ex: array('subject' => '/^Hello, Alice!/').
690 * Keys: subject, body_text, body_html, from_name, from_email.
691 * @dataProvider mailerExamples
692 */
693 public function testMailer($schedule, $patterns) {
694 $actionSchedule = array_merge($this->fixtures['sched_activity_1day'], $schedule);
695 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
696 $this->assertTrue(is_numeric($actionScheduleDao->id));
697
698 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
699 $this->assertTrue(is_numeric($activity->id));
700 $contact = $this->callAPISuccess('contact', 'create', $this->fixtures['contact']);
701 $activity->save();
702
703 $source['contact_id'] = $contact['id'];
704 $source['activity_id'] = $activity->id;
705 $source['record_type_id'] = 2;
706 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
707 $activityContact->save();
708
709 CRM_Utils_Time::setTime('2012-06-14 15:00:00');
710 $this->callAPISuccess('job', 'send_reminder', array());
711 $this->mut->assertRecipients(array(array('test-member@example.com')));
712 foreach ($this->mut->getAllMessages('ezc') as $message) {
713 /** @var ezcMail $message */
714
715 $messageArray = array();
716 $messageArray['subject'] = $message->subject;
717 $messageArray['from_name'] = $message->from->name;
718 $messageArray['from_email'] = $message->from->email;
719 $messageArray['body_text'] = '--UNDEFINED--';
720 $messageArray['body_html'] = '--UNDEFINED--';
721
722 foreach ($message->fetchParts() as $part) {
723 /** @var ezcMailText ezcMailText */
724 if ($part instanceof ezcMailText && $part->subType == 'html') {
725 $messageArray['body_html'] = $part->text;
726 }
727 if ($part instanceof ezcMailText && $part->subType == 'plain') {
728 $messageArray['body_text'] = $part->text;
729 }
730 }
731
732 foreach ($patterns as $field => $pattern) {
733 $this->assertRegExp($pattern, $messageArray[$field],
734 "Check that '$field'' matches regex. " . print_r(array('expected' => $patterns, 'actual' => $messageArray), 1));
735 }
736 }
737 $this->mut->clearMessages();
738
739 }
740
741 public function testActivityDateTimeMatchNonRepeatableSchedule() {
742 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($this->fixtures['sched_activity_1day']);
743 $this->assertTrue(is_numeric($actionScheduleDao->id));
744
745 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
746 $this->assertTrue(is_numeric($activity->id));
747 $contact = $this->callAPISuccess('contact', 'create', $this->fixtures['contact']);
748 $activity->save();
749
750 $source['contact_id'] = $contact['id'];
751 $source['activity_id'] = $activity->id;
752 $source['record_type_id'] = 2;
753 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
754 $activityContact->save();
755
756 $this->assertCronRuns(array(
757 array(
758 // Before the 24-hour mark, no email
759 'time' => '2012-06-14 04:00:00',
760 'recipients' => array(),
761 'subjects' => array(),
762 ),
763 array(
764 // After the 24-hour mark, an email
765 'time' => '2012-06-14 15:00:00',
766 'recipients' => array(array('test-member@example.com')),
767 'subjects' => array('1-Day (non-repeating) (about Phone Call)'),
768 ),
769 array(
770 // Run cron again; message already sent
771 'time' => '',
772 'recipients' => array(),
773 ),
774 ));
775 }
776
777 public function testActivityDateTimeMatchRepeatableSchedule() {
778 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($this->fixtures['sched_activity_1day_r']);
779 $this->assertTrue(is_numeric($actionScheduleDao->id));
780
781 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
782 $this->assertTrue(is_numeric($activity->id));
783 $contact = $this->callAPISuccess('contact', 'create', $this->fixtures['contact']);
784 $activity->save();
785
786 $source['contact_id'] = $contact['id'];
787 $source['activity_id'] = $activity->id;
788 $source['record_type_id'] = 2;
789 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
790 $activityContact->save();
791
792 $this->assertCronRuns(array(
793 array(
794 // Before the 24-hour mark, no email
795 'time' => '012-06-14 04:00:00',
796 'recipients' => array(),
797 'subjects' => array(),
798 ),
799 array(
800 // After the 24-hour mark, an email
801 'time' => '2012-06-14 15:00:00',
802 'recipients' => array(array('test-member@example.com')),
803 'subjects' => array('1-Day (repeating) (about Phone Call)'),
804 ),
805 array(
806 // Run cron 4 hours later; first message already sent
807 'time' => '2012-06-14 20:00:00',
808 'recipients' => array(),
809 'subjects' => array(),
810 ),
811 array(
812 // Run cron 6 hours later; send second message.
813 'time' => '2012-06-14 21:00:01',
814 'recipients' => array(array('test-member@example.com')),
815 'subjects' => array('1-Day (repeating) (about Phone Call)'),
816 ),
817 ));
818 }
819
820 /**
821 * For contacts/activities which don't match the schedule filter,
822 * an email should *not* be sent.
823 */
824 // TODO // function testActivityDateTime_NonMatch() { }
825
826 /**
827 * For contacts/members which match schedule based on join date,
828 * an email should be sent.
829 */
830 public function testMembershipJoinDateMatch() {
831 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 1)));
832 $this->assertTrue(is_numeric($membership->id));
833 $result = $this->callAPISuccess('Email', 'create', array(
834 'contact_id' => $membership->contact_id,
835 'email' => 'test-member@example.com',
836 'location_type_id' => 1,
837 ));
838 $this->assertAPISuccess($result);
839
840 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
841 $actionSchedule = $this->fixtures['sched_membership_join_2week'];
842 $actionSchedule['entity_value'] = $membership->membership_type_id;
843 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
844 $this->assertTrue(is_numeric($actionScheduleDao->id));
845
846 // start_date=2012-03-15 ; schedule is 2 weeks after start_date
847 $this->assertCronRuns(array(
848 array(
849 // Before the 2-week mark, no email.
850 'time' => '2012-03-28 01:00:00',
851 'recipients' => array(),
852 'subjects' => array(),
853 ),
854 array(
855 // After the 2-week mark, send an email.
856 'time' => '2012-03-29 01:00:00',
857 'recipients' => array(array('test-member@example.com')),
858 'subjects' => array('subject sched_membership_join_2week (joined March 15th, 2012)'),
859 ),
860 ));
861 }
862
863 /**
864 * Test end date email sent.
865 *
866 * For contacts/members which match schedule based on join date,
867 * an email should be sent.
868 */
869 public function testMembershipJoinDateNonMatch() {
870 $membership = $this->createTestObject('CRM_Member_DAO_Membership', $this->fixtures['rolling_membership']);
871 $this->assertTrue(is_numeric($membership->id));
872 $result = $this->callAPISuccess('Email', 'create', array(
873 'contact_id' => $membership->contact_id,
874 'location_type_id' => 1,
875 'email' => 'test-member@example.com',
876 ));
877
878 // Add an alternative membership type, and only send messages for that type
879 $extraMembershipType = $this->createTestObject('CRM_Member_DAO_MembershipType', array());
880 $this->assertTrue(is_numeric($extraMembershipType->id));
881 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($this->fixtures['sched_membership_join_2week']);
882 $this->assertTrue(is_numeric($actionScheduleDao->id));
883 $actionScheduleDao->entity_value = $extraMembershipType->id;
884 $actionScheduleDao->save();
885
886 // start_date=2012-03-15 ; schedule is 2 weeks after start_date
887 $this->assertCronRuns(array(
888 array(
889 // After the 2-week mark, don't send email because we have different membership type.
890 'time' => '2012-03-29 01:00:00',
891 'recipients' => array(),
892 ),
893 ));
894 }
895
896 /**
897 * Test that the first and SECOND notifications are sent out.
898 */
899 public function testMembershipEndDateRepeat() {
900 // creates membership with end_date = 20120615
901 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 2)));
902 $result = $this->callAPISuccess('Email', 'create', array(
903 'contact_id' => $membership->contact_id,
904 'email' => 'test-member@example.com',
905 ));
906 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
907
908 $actionSchedule = $this->fixtures['sched_membership_end_2month_repeat_twice_4_weeks'];
909 $actionSchedule['entity_value'] = $membership->membership_type_id;
910 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
911
912 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
913 $this->assertCronRuns(array(
914 array(
915 // After the 2-week mark, send an email.
916 'time' => '2012-08-15 01:00:00',
917 'recipients' => array(array('test-member@example.com')),
918 ),
919 array(
920 // After the 2-week mark, send an email.
921 'time' => '2012-09-12 01:00:00',
922 'recipients' => array(array('test-member@example.com')),
923 ),
924 ));
925 }
926
927 /**
928 * Test behaviour when date changes.
929 *
930 * Test that the first notification is sent but the second is NOT sent if the end date changes in
931 * between
932 * see CRM-15376
933 */
934 public function testMembershipEndDateRepeatChangedEndDate_CRM_15376() {
935 // creates membership with end_date = 20120615
936 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 2)));
937 $this->callAPISuccess('Email', 'create', array(
938 'contact_id' => $membership->contact_id,
939 'email' => 'test-member@example.com',
940 ));
941 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
942
943 $actionSchedule = $this->fixtures['sched_membership_end_2month_repeat_twice_4_weeks'];
944 $actionSchedule['entity_value'] = $membership->membership_type_id;
945 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
946 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
947 $this->assertCronRuns(array(
948 array(
949 // After the 2-week mark, send an email.
950 'time' => '2012-08-15 01:00:00',
951 'recipients' => array(array('test-member@example.com')),
952 ),
953 ));
954
955 // Extend membership - reminder should NOT go out.
956 $this->callAPISuccess('membership', 'create', array('id' => $membership->id, 'end_date' => '2014-01-01'));
957 $this->assertCronRuns(array(
958 array(
959 // After the 2-week mark, send an email.
960 'time' => '2012-09-12 01:00:00',
961 'recipients' => array(),
962 ),
963 ));
964 }
965
966 /**
967 * Test membership end date email sends.
968 *
969 * For contacts/members which match schedule based on end date,
970 * an email should be sent.
971 */
972 public function testMembershipEndDateMatch() {
973 // creates membership with end_date = 20120615
974 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 2)));
975 $this->assertTrue(is_numeric($membership->id));
976 $this->callAPISuccess('Email', 'create', array(
977 'contact_id' => $membership->contact_id,
978 'email' => 'test-member@example.com',
979 ));
980 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
981
982 $actionSchedule = $this->fixtures['sched_membership_end_2week'];
983 $actionSchedule['entity_value'] = $membership->membership_type_id;
984 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
985 $this->assertTrue(is_numeric($actionScheduleDao->id));
986
987 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
988 $this->assertCronRuns(array(
989 array(
990 // Before the 2-week mark, no email.
991 'time' => '2012-05-31 01:00:00',
992 // 'time' => '2012-06-01 01:00:00',
993 // FIXME: Is this the right boundary?
994 'recipients' => array(),
995 ),
996 array(
997 // After the 2-week mark, send an email.
998 'time' => '2012-06-01 01:00:00',
999 'recipients' => array(array('test-member@example.com')),
1000 ),
1001 ));
1002
1003 // Now suppose user has renewed for rolling membership after 3 months, so upcoming assertion is written
1004 // to ensure that new reminder is sent 2 week before the new end_date i.e. '2012-09-15'
1005 $membership->end_date = '2012-09-15';
1006 $membership->save();
1007
1008 //change the email id of chosen membership contact to assert
1009 //recipient of not the previously sent mail but the new one
1010 $result = $this->callAPISuccess('Email', 'create', array(
1011 'is_primary' => 1,
1012 'contact_id' => $membership->contact_id,
1013 'email' => 'member2@example.com',
1014 ));
1015 $this->assertAPISuccess($result);
1016
1017 // end_date=2012-09-15 ; schedule is 2 weeks before end_date
1018 $this->assertCronRuns(array(
1019 array(
1020 // Before the 2-week mark, no email
1021 'time' => '2012-08-31 01:00:00',
1022 'recipients' => array(),
1023 ),
1024 //array( // After the 2-week mark, send an email
1025 //'time' => '2012-09-01 01:00:00',
1026 //'recipients' => array(array('member2@example.com')),
1027 //),
1028 ));
1029 }
1030
1031
1032 /**
1033 * Test membership end date email.
1034 *
1035 * For contacts/members which match schedule based on end date,
1036 * an email should be sent.
1037 */
1038 public function testMembershipEndDateNoMatch() {
1039 // creates membership with end_date = 20120615
1040 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 3)));
1041 $this->assertTrue(is_numeric($membership->id));
1042 $result = $this->callAPISuccess('Email', 'create', array(
1043 'contact_id' => $membership->contact_id,
1044 'email' => 'test-member@example.com',
1045 ));
1046 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
1047
1048 $actionSchedule = $this->fixtures['sched_membership_end_2month'];
1049 $actionSchedule['entity_value'] = $membership->membership_type_id;
1050 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1051 $this->assertTrue(is_numeric($actionScheduleDao->id));
1052
1053 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
1054 $this->assertCronRuns(array(
1055 array(
1056 // Before the 2-week mark, no email.
1057 'time' => '2012-05-31 01:00:00',
1058 // 'time' => '2012-06-01 01:00:00',
1059 // FIXME: Is this the right boundary?
1060 'recipients' => array(),
1061 ),
1062 array(
1063 // After the 2-week mark, send an email.
1064 'time' => '2013-05-01 01:00:00',
1065 'recipients' => array(),
1066 ),
1067 ));
1068 }
1069
1070 public function testContactBirthDateNoAnniv() {
1071 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
1072 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1073 $actionSchedule = $this->fixtures['sched_contact_bday_yesterday'];
1074 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1075 $this->assertTrue(is_numeric($actionScheduleDao->id));
1076 $this->assertCronRuns(array(
1077 array(
1078 // On the birthday, no email.
1079 'time' => '2005-07-07 01:00:00',
1080 'recipients' => array(),
1081 ),
1082 array(
1083 // The next day, send an email.
1084 'time' => '2005-07-08 20:00:00',
1085 'recipients' => array(array('test-bday@example.com')),
1086 ),
1087 ));
1088 }
1089
1090 public function testContactBirthDateAnniversary() {
1091 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
1092 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1093 $actionSchedule = $this->fixtures['sched_contact_bday_anniv'];
1094 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1095 $this->assertTrue(is_numeric($actionScheduleDao->id));
1096 $this->assertCronRuns(array(
1097 array(
1098 // On some random day, no email.
1099 'time' => '2014-03-07 01:00:00',
1100 'recipients' => array(),
1101 ),
1102 array(
1103 // On the eve of their 9th birthday, send an email.
1104 'time' => '2014-07-06 20:00:00',
1105 'recipients' => array(array('test-bday@example.com')),
1106 ),
1107 ));
1108 }
1109
1110 public function testContactCustomDateNoAnniv() {
1111 $group = array(
1112 'title' => 'Test_Group',
1113 'name' => 'test_group',
1114 'extends' => array('Individual'),
1115 'style' => 'Inline',
1116 'is_multiple' => FALSE,
1117 'is_active' => 1,
1118 );
1119 $createGroup = $this->callAPISuccess('custom_group', 'create', $group);
1120 $field = array(
1121 'label' => 'Graduation',
1122 'data_type' => 'Date',
1123 'html_type' => 'Select Date',
1124 'custom_group_id' => $createGroup['id'],
1125 );
1126 $createField = $this->callAPISuccess('custom_field', 'create', $field);
1127 $contactParams = $this->fixtures['contact'];
1128 $contactParams["custom_{$createField['id']}"] = '2013-12-16';
1129 $contact = $this->callAPISuccess('Contact', 'create', $contactParams);
1130 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1131 $actionSchedule = $this->fixtures['sched_contact_grad_tomorrow'];
1132 $actionSchedule['entity_value'] = "custom_{$createField['id']}";
1133 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1134 $this->assertTrue(is_numeric($actionScheduleDao->id));
1135 $this->assertCronRuns(array(
1136 array(
1137 // On some random day, no email.
1138 'time' => '2014-03-07 01:00:00',
1139 'recipients' => array(),
1140 ),
1141 array(
1142 // On the eve of their graduation, send an email.
1143 'time' => '2013-12-15 20:00:00',
1144 'recipients' => array(array('test-member@example.com')),
1145 ),
1146 ));
1147 $this->callAPISuccess('custom_group', 'delete', array('id' => $createGroup['id']));
1148 }
1149
1150 public function testContactCreatedNoAnniv() {
1151 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
1152 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1153 $actionSchedule = $this->fixtures['sched_contact_created_yesterday'];
1154 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1155 $this->assertTrue(is_numeric($actionScheduleDao->id));
1156 $this->assertCronRuns(array(
1157 array(
1158 // On the date created, no email.
1159 'time' => $contact['values'][$contact['id']]['created_date'],
1160 'recipients' => array(),
1161 ),
1162 array(
1163 // The next day, send an email.
1164 'time' => date('Y-m-d H:i:s', strtotime($contact['values'][$contact['id']]['created_date'] . ' +1 day')),
1165 'recipients' => array(array('test-bday@example.com')),
1166 ),
1167 ));
1168 }
1169
1170 public function testContactModifiedAnniversary() {
1171 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
1172 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1173 $actionSchedule = $this->fixtures['sched_contact_mod_anniv'];
1174 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1175 $this->assertTrue(is_numeric($actionScheduleDao->id));
1176 $this->assertCronRuns(array(
1177 array(
1178 // On some random day, no email.
1179 'time' => date('Y-m-d H:i:s', strtotime($contact['values'][$contact['id']]['modified_date'] . ' -60 days')),
1180 'recipients' => array(),
1181 ),
1182 array(
1183 // On the eve of 3 years after they were modified, send an email.
1184 'time' => date('Y-m-d H:i:s', strtotime($contact['values'][$contact['id']]['modified_date'] . ' +3 years -23 hours')),
1185 'recipients' => array(array('test-bday@example.com')),
1186 ),
1187 ));
1188 }
1189
1190 /**
1191 * Check that limit_to + an empty recipients doesn't sent to multiple contacts.
1192 */
1193 public function testMembershipLimitToNone() {
1194 // creates membership with end_date = 20120615
1195 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 2)));
1196
1197 $this->assertTrue(is_numeric($membership->id));
1198 $result = $this->callAPISuccess('Email', 'create', array(
1199 'contact_id' => $membership->contact_id,
1200 'email' => 'member@example.com',
1201 ));
1202 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
1203 $this->callAPISuccess('contact', 'create', array('email' => 'b@c.com', 'contact_type' => 'Individual'));
1204
1205 $this->assertAPISuccess($result);
1206
1207 $actionSchedule = $this->fixtures['sched_membership_end_limit_to_none'];
1208 $actionSchedule['entity_value'] = $membership->membership_type_id;
1209 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1210 $this->assertTrue(is_numeric($actionScheduleDao->id));
1211
1212 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
1213 $this->assertCronRuns(array(
1214 array(
1215 // Before the 2-week mark, no email.
1216 'time' => '2012-05-31 01:00:00',
1217 // 'time' => '2012-06-01 01:00:00', // FIXME: Is this the right boundary?
1218 'recipients' => array(),
1219 ),
1220 ));
1221 }
1222
1223 public function testMembership_referenceDate() {
1224 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 2)));
1225
1226 $this->assertTrue(is_numeric($membership->id));
1227 $result = $this->callAPISuccess('Email', 'create', array(
1228 'contact_id' => $membership->contact_id,
1229 'email' => 'member@example.com',
1230 ));
1231
1232 $result = $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
1233 $this->assertAPISuccess($result);
1234
1235 $actionSchedule = $this->fixtures['sched_membership_join_2week'];
1236 $actionSchedule['entity_value'] = $membership->membership_type_id;
1237 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1238 $this->assertTrue(is_numeric($actionScheduleDao->id));
1239
1240 // start_date=2012-03-15 ; schedule is 2 weeks after start_date
1241 $this->assertCronRuns(array(
1242 array(
1243 // After the 2-week mark, send an email
1244 'time' => '2012-03-29 01:00:00',
1245 'recipients' => array(array('member@example.com')),
1246 ),
1247 array(
1248 // After the 2-week 1day mark, don't send an email
1249 'time' => '2012-03-30 01:00:00',
1250 'recipients' => array(),
1251 ),
1252 ));
1253
1254 //check if reference date is set to membership's join date
1255 //as per the action_start_date chosen for current schedule reminder
1256 $this->assertEquals('2012-03-15',
1257 CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $membership->contact_id, 'reference_date', 'contact_id')
1258 );
1259
1260 //change current membership join date that may signifies as membership renewal activity
1261 $membership->join_date = '2012-03-29';
1262 $membership->save();
1263
1264 $this->assertCronRuns(array(
1265 array(
1266 // After the 13 days of the changed join date 2012-03-29, don't send an email
1267 'time' => '2012-04-11 01:00:00',
1268 'recipients' => array(),
1269 ),
1270 array(
1271 // After the 2-week of the changed join date 2012-03-29, send an email
1272 'time' => '2012-04-12 01:00:00',
1273 'recipients' => array(array('member@example.com')),
1274 ),
1275 ));
1276 }
1277
1278 public function testMembershipOnMultipleReminder() {
1279 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], array('status_id' => 2)));
1280
1281 $this->assertTrue(is_numeric($membership->id));
1282 $result = $this->callAPISuccess('Email', 'create', array(
1283 'contact_id' => $membership->contact_id,
1284 'email' => 'member@example.com',
1285 ));
1286 $result = $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $membership->contact_id)));
1287 $this->assertAPISuccess($result);
1288
1289 $actionScheduleBefore = $this->fixtures['sched_membership_end_2week']; // Send email 2 weeks before end_date
1290 $actionScheduleOn = $this->fixtures['sched_on_membership_end_date']; // Send email on end_date/expiry date
1291 $actionScheduleAfter = $this->fixtures['sched_after_1day_membership_end_date']; // Send email 1 day after end_date/grace period
1292 $actionScheduleBefore['entity_value'] = $actionScheduleOn['entity_value'] = $actionScheduleAfter['entity_value'] = $membership->membership_type_id;
1293 foreach (array('actionScheduleBefore', 'actionScheduleOn', 'actionScheduleAfter') as $value) {
1294 $$value = CRM_Core_BAO_ActionSchedule::add($$value);
1295 $this->assertTrue(is_numeric($$value->id));
1296 }
1297
1298 $this->assertCronRuns(
1299 array(
1300 array(
1301 // 1day 2weeks before membership end date(MED), don't send mail
1302 'time' => '2012-05-31 01:00:00',
1303 'recipients' => array(),
1304 ),
1305 array(
1306 // 2 weeks before MED, send an email
1307 'time' => '2012-06-01 01:00:00',
1308 'recipients' => array(array('member@example.com')),
1309 ),
1310 array(
1311 // 1day before MED, don't send mail
1312 'time' => '2012-06-14 01:00:00',
1313 'recipients' => array(),
1314 ),
1315 array(
1316 // On MED, send an email
1317 'time' => '2012-06-15 00:00:00',
1318 'recipients' => array(array('member@example.com')),
1319 ),
1320 array(
1321 // After 1day of MED, send an email
1322 'time' => '2012-06-16 01:00:00',
1323 'recipients' => array(array('member@example.com')),
1324 ),
1325 array(
1326 // After 1day 1min of MED, don't send an email
1327 'time' => '2012-06-17 00:01:00',
1328 'recipients' => array(),
1329 ),
1330 )
1331 );
1332
1333 // Assert the timestamp as of when the emails of respective three reminders as configured
1334 // 2 weeks before, on and 1 day after MED, are sent
1335 $this->assertApproxEquals(
1336 strtotime('2012-06-01 01:00:00'),
1337 strtotime(CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $actionScheduleBefore->id, 'action_date_time', 'action_schedule_id', TRUE)),
1338 3 // Variation in test execution time.
1339 );
1340 $this->assertApproxEquals(
1341 strtotime('2012-06-15 00:00:00'),
1342 strtotime(CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $actionScheduleOn->id, 'action_date_time', 'action_schedule_id', TRUE)),
1343 3 // Variation in test execution time.
1344 );
1345 $this->assertApproxEquals(
1346 strtotime('2012-06-16 01:00:00'),
1347 strtotime(CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $actionScheduleAfter->id, 'action_date_time', 'action_schedule_id', TRUE)),
1348 3 // Variation in test execution time.
1349 );
1350
1351 //extend MED to 2 weeks after the current MED (that may signifies as membership renewal activity)
1352 // and lets assert as of when the new set of reminders will be sent against their respective Schedule Reminders(SR)
1353 $membership->end_date = '2012-06-20';
1354 $membership->save();
1355
1356 $result = $this->callAPISuccess('Contact', 'get', array('id' => $membership->contact_id));
1357 $this->assertCronRuns(
1358 array(
1359 array(
1360 // 1day 2weeks before membership end date(MED), don't send mail
1361 'time' => '2012-06-05 01:00:00',
1362 'recipients' => array(),
1363 ),
1364 array(
1365 // 2 weeks before MED, send an email
1366 'time' => '2012-06-06 01:00:00',
1367 'recipients' => array(array('member@example.com')),
1368 ),
1369 array(
1370 // 1day before MED, don't send mail
1371 'time' => '2012-06-19 01:00:00',
1372 'recipients' => array(),
1373 ),
1374 array(
1375 // On MED, send an email
1376 'time' => '2012-06-20 00:00:00',
1377 'recipients' => array(array('member@example.com')),
1378 ),
1379 array(
1380 // After 1day of MED, send an email
1381 'time' => '2012-06-21 01:00:00',
1382 'recipients' => array(array('member@example.com')),
1383 ),
1384 array(
1385 // After 1day 1min of MED, don't send an email
1386 'time' => '2012-07-21 00:01:00',
1387 'recipients' => array(),
1388 ),
1389 ));
1390 }
1391
1392 public function testContactCustomDate_Anniv() {
1393 $group = array(
1394 'title' => 'Test_Group now',
1395 'name' => 'test_group_now',
1396 'extends' => array('Individual'),
1397 'style' => 'Inline',
1398 'is_multiple' => FALSE,
1399 'is_active' => 1,
1400 );
1401 $createGroup = $this->callAPISuccess('custom_group', 'create', $group);
1402 $field = array(
1403 'label' => 'Graduation',
1404 'data_type' => 'Date',
1405 'html_type' => 'Select Date',
1406 'custom_group_id' => $createGroup['id'],
1407 );
1408 $createField = $this->callAPISuccess('custom_field', 'create', $field);
1409
1410 $contactParams = $this->fixtures['contact'];
1411 $contactParams["custom_{$createField['id']}"] = '2013-12-16';
1412 $contact = $this->callAPISuccess('Contact', 'create', $contactParams);
1413 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1414 $actionSchedule = $this->fixtures['sched_contact_grad_anniv'];
1415 $actionSchedule['entity_value'] = "custom_{$createField['id']}";
1416 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1417 $this->assertTrue(is_numeric($actionScheduleDao->id));
1418 $this->assertCronRuns(array(
1419 array(
1420 // On some random day, no email.
1421 'time' => '2014-03-07 01:00:00',
1422 'recipients' => array(),
1423 ),
1424 array(
1425 // A week after their 5th anniversary of graduation, send an email.
1426 'time' => '2018-12-23 20:00:00',
1427 'recipients' => array(array('test-member@example.com')),
1428 ),
1429 ));
1430 $this->callAPISuccess('custom_group', 'delete', array('id' => $createGroup['id']));
1431 }
1432
1433 public function testEventTypeStartDate() {
1434 // Create event+participant with start_date = 20120315, end_date = 20120615.
1435 $participant = $this->createTestObject('CRM_Event_DAO_Participant', array_merge($this->fixtures['participant'], array('status_id' => 2)));
1436 $this->callAPISuccess('Email', 'create', array(
1437 'contact_id' => $participant->contact_id,
1438 'email' => 'test-event@example.com',
1439 ));
1440 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $participant->contact_id)));
1441
1442 $actionSchedule = $this->fixtures['sched_eventtype_start_1week_before'];
1443 $actionSchedule['entity_value'] = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $participant->event_id, 'event_type_id');
1444 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
1445
1446 //echo "CREATED\n"; ob_flush(); sleep(20);
1447
1448 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
1449 $this->assertCronRuns(array(
1450 array(
1451 // 2 weeks before
1452 'time' => '2012-03-02 01:00:00',
1453 'recipients' => array(),
1454 ),
1455 array(
1456 // 1 week before
1457 'time' => '2012-03-08 01:00:00',
1458 'recipients' => array(array('test-event@example.com')),
1459 ),
1460 array(
1461 // And then nothing else
1462 'time' => '2012-03-16 01:00:00',
1463 'recipients' => array(),
1464 ),
1465 ));
1466 }
1467
1468 public function testEventTypeEndDateRepeat() {
1469 // Create event+participant with start_date = 20120315, end_date = 20120615.
1470 $participant = $this->createTestObject('CRM_Event_DAO_Participant', array_merge($this->fixtures['participant'], array('status_id' => 2)));
1471 $this->callAPISuccess('Email', 'create', array(
1472 'contact_id' => $participant->contact_id,
1473 'email' => 'test-event@example.com',
1474 ));
1475 $c = $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], array('contact_id' => $participant->contact_id)));
1476
1477 $actionSchedule = $this->fixtures['sched_eventtype_end_2month_repeat_twice_2_weeks'];
1478 $actionSchedule['entity_value'] = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $participant->event_id, 'event_type_id');
1479 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
1480
1481 $this->assertCronRuns(array(
1482 array(
1483 // Almost 2 months.
1484 'time' => '2012-08-13 01:00:00',
1485 'recipients' => array(),
1486 ),
1487 array(
1488 // After the 2-month mark, send an email.
1489 'time' => '2012-08-16 01:00:00',
1490 'recipients' => array(array('test-event@example.com')),
1491 ),
1492 array(
1493 // After 2 months and 1 week, don't repeat yet.
1494 'time' => '2012-08-23 02:00:00',
1495 'recipients' => array(),
1496 ),
1497 array(
1498 // After 2 months and 2 weeks
1499 'time' => '2012-08-30 02:00:00',
1500 'recipients' => array(array('test-event@example.com')),
1501 ),
1502 array(
1503 // After 2 months and 4 week
1504 'time' => '2012-09-13 02:00:00',
1505 'recipients' => array(array('test-event@example.com')),
1506 ),
1507 array(
1508 // After 2 months and 6 weeks
1509 'time' => '2012-09-27 01:00:00',
1510 'recipients' => array(),
1511 ),
1512 ));
1513 }
1514
1515 // TODO // function testMembershipEndDate_NonMatch() { }
1516 // TODO // function testEventTypeStartDate_Match() { }
1517 // TODO // function testEventTypeEndDate_Match() { }
1518 // TODO // function testEventNameStartDate_Match() { }
1519 // TODO // function testEventNameEndDate_Match() { }
1520
1521 /**
1522 * Run a series of cron jobs and make an assertion about email deliveries.
1523 *
1524 * @param array $cronRuns
1525 * array specifying when to run cron and what messages to expect; each item is an array with keys:
1526 * - time: string, e.g. '2012-06-15 21:00:01'
1527 * - recipients: array(array(string)), list of email addresses which should receive messages
1528 */
1529 public function assertCronRuns($cronRuns) {
1530 foreach ($cronRuns as $cronRun) {
1531 CRM_Utils_Time::setTime($cronRun['time']);
1532 $this->callAPISuccess('job', 'send_reminder', array());
1533 $this->mut->assertRecipients($cronRun['recipients']);
1534 if (array_key_exists('subjects', $cronRun)) {
1535 $this->mut->assertSubjects($cronRun['subjects']);
1536 }
1537 $this->mut->clearMessages();
1538 }
1539 }
1540
1541 /**
1542 * @var array(DAO_Name => array(int)) List of items to garbage-collect during tearDown
1543 */
1544 private $_testObjects;
1545
1546 /**
1547 * Sets up the fixture, for example, opens a network connection.
1548 *
1549 * This method is called before a test is executed.
1550 */
1551 protected function _setUp() {
1552 $this->_testObjects = array();
1553 }
1554
1555 /**
1556 * Tears down the fixture, for example, closes a network connection.
1557 *
1558 * This method is called after a test is executed.
1559 */
1560 protected function _tearDown() {
1561 parent::tearDown();
1562 $this->deleteTestObjects();
1563 }
1564
1565 /**
1566 * This is a wrapper for CRM_Core_DAO::createTestObject which tracks
1567 * created entities and provides for brainless cleanup.
1568 *
1569 * @see CRM_Core_DAO::createTestObject
1570 *
1571 * @param $daoName
1572 * @param array $params
1573 * @param int $numObjects
1574 * @param bool $createOnly
1575 *
1576 * @return array|NULL|object
1577 */
1578 public function createTestObject($daoName, $params = array(), $numObjects = 1, $createOnly = FALSE) {
1579 $objects = CRM_Core_DAO::createTestObject($daoName, $params, $numObjects, $createOnly);
1580 if (is_array($objects)) {
1581 $this->registerTestObjects($objects);
1582 }
1583 else {
1584 $this->registerTestObjects(array($objects));
1585 }
1586 return $objects;
1587 }
1588
1589 /**
1590 * @param array $objects
1591 * DAO or BAO objects.
1592 */
1593 public function registerTestObjects($objects) {
1594 //if (is_object($objects)) {
1595 // $objects = array($objects);
1596 //}
1597 foreach ($objects as $object) {
1598 $daoName = preg_replace('/_BAO_/', '_DAO_', get_class($object));
1599 $this->_testObjects[$daoName][] = $object->id;
1600 }
1601 }
1602
1603 public function deleteTestObjects() {
1604 // Note: You might argue that the FK relations between test
1605 // objects could make this problematic; however, it should
1606 // behave intuitively as long as we mentally split our
1607 // test-objects between the "manual/primary records"
1608 // and the "automatic/secondary records"
1609 foreach ($this->_testObjects as $daoName => $daoIds) {
1610 foreach ($daoIds as $daoId) {
1611 CRM_Core_DAO::deleteTestObjects($daoName, array('id' => $daoId));
1612 }
1613 }
1614 $this->_testObjects = array();
1615 }
1616
1617 }