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