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