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