Merge pull request #17152 from eileenmcnaughton/act2
[civicrm-core.git] / tests / phpunit / CRM / Core / BAO / ActionScheduleTest.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7d61e75f 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
7d61e75f
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035 11
e9479dcf
EM
12/**
13 * Class CRM_Core_BAO_ActionScheduleTest
2a21d018 14 * @group ActionSchedule
acb109b7 15 * @group headless
2a21d018
TO
16 *
17 * There are additional tests for some specific entities in other classes:
18 * @see CRM_Activity_ActionMappingTest
19 * @see CRM_Contribute_ActionMapping_ByTypeTest
e9479dcf 20 */
6a488035 21class CRM_Core_BAO_ActionScheduleTest extends CiviUnitTestCase {
63e9c3fd 22
6a488035 23 /**
f8c3594b 24 * @var CiviMailUtils
6a488035 25 */
567b2076 26 public $mut;
cee19268 27
34662dda 28 /**
29 * Entities set up for the test.
30 *
31 * @var array
32 */
33 private $fixtures = [];
34
35 /**
36 * Setup for tests.
37 *
38 * @throws CRM_Core_Exception
39 */
00be9182 40 public function setUp() {
6a488035
TO
41 parent::setUp();
42
6c6e6187 43 $this->mut = new CiviMailUtils($this, TRUE);
6a488035 44
9099cab3 45 $this->fixtures['rolling_membership_type'] = [
e08fae02
PH
46 'period_type' => 'rolling',
47 'duration_unit' => 'month',
48 'duration_interval' => '3',
49 'is_active' => 1,
50 'domain_id' => 1,
51 'financial_type_id' => 2,
9099cab3 52 ];
e08fae02 53
9099cab3
CW
54 $this->fixtures['rolling_membership'] = [
55 'membership_type_id' => [
6a488035
TO
56 'period_type' => 'rolling',
57 'duration_unit' => 'month',
58 'duration_interval' => '3',
59 'is_active' => 1,
9099cab3 60 ],
6a488035
TO
61 'join_date' => '20120315',
62 'start_date' => '20120315',
63 'end_date' => '20120615',
b29be8c2 64 'is_override' => 0,
9099cab3 65 ];
4b1efa1d 66
9099cab3
CW
67 $this->fixtures['rolling_membership_past'] = [
68 'membership_type_id' => [
4b1efa1d 69 'period_type' => 'rolling',
70 'duration_unit' => 'month',
71 'duration_interval' => '3',
72 'is_active' => 1,
9099cab3 73 ],
4b1efa1d 74 'join_date' => '20100310',
75 'start_date' => '20100310',
76 'end_date' => '20100610',
77 'is_override' => 'NULL',
9099cab3
CW
78 ];
79 $this->fixtures['participant'] = [
80 'event_id' => [
d3eae6ea
TO
81 'is_active' => 1,
82 'is_template' => 0,
83 'title' => 'Example Event',
84 'start_date' => '20120315',
85 'end_date' => '20120615',
9099cab3 86 ],
39b959db
SL
87 // Attendee.
88 'role_id' => '1',
89 // No-show.
90 'status_id' => '8',
9099cab3 91 ];
fe265b4e 92
9099cab3 93 $this->fixtures['phonecall'] = [
6a488035
TO
94 'status_id' => 1,
95 'activity_type_id' => 2,
96 'activity_date_time' => '20120615100000',
97 'is_current_revision' => 1,
98 'is_deleted' => 0,
9099cab3
CW
99 ];
100 $this->fixtures['contact'] = [
b29be8c2 101 'is_deceased' => 0,
6a488035
TO
102 'contact_type' => 'Individual',
103 'email' => 'test-member@example.com',
43ceab3f 104 'gender_id' => 'Female',
bba4f3f6
CB
105 'first_name' => 'Churmondleia',
106 'last_name' => 'Ōtākou',
9099cab3
CW
107 ];
108 $this->fixtures['contact_2'] = [
e08fae02
PH
109 'is_deceased' => 0,
110 'contact_type' => 'Individual',
111 'email' => 'test-contact-2@example.com',
112 'gender_id' => 'Male',
113 'first_name' => 'Fabble',
114 'last_name' => 'Fi',
9099cab3
CW
115 ];
116 $this->fixtures['contact_birthdate'] = [
43030baf
AH
117 'is_deceased' => 0,
118 'contact_type' => 'Individual',
119 'email' => 'test-bday@example.com',
120 'birth_date' => '20050707',
9099cab3
CW
121 ];
122 $this->fixtures['sched_activity_1day'] = [
6a488035
TO
123 'name' => 'One_Day_Phone_Call_Notice',
124 'title' => 'One Day Phone Call Notice',
84a3e359 125 'limit_to' => '1',
6a488035 126 'absolute_date' => NULL,
d19632b1
JP
127 'body_html' => '<p>1-Day (non-repeating) (for {activity.subject})</p>',
128 'body_text' => '1-Day (non-repeating) (for {activity.subject})',
6a488035
TO
129 'end_action' => NULL,
130 'end_date' => NULL,
131 'end_frequency_interval' => NULL,
132 'end_frequency_unit' => NULL,
133 'entity_status' => '1',
134 'entity_value' => '2',
135 'group_id' => NULL,
136 'is_active' => '1',
137 'is_repeat' => '0',
138 'mapping_id' => '1',
139 'msg_template_id' => NULL,
140 'recipient' => '2',
141 'recipient_listing' => NULL,
142 'recipient_manual' => NULL,
d19632b1 143 'record_activity' => 1,
6a488035
TO
144 'repetition_frequency_interval' => NULL,
145 'repetition_frequency_unit' => NULL,
146 'start_action_condition' => 'before',
147 'start_action_date' => 'activity_date_time',
148 'start_action_offset' => '1',
149 'start_action_unit' => 'day',
f8c3594b 150 'subject' => '1-Day (non-repeating) (about {activity.activity_type})',
9099cab3
CW
151 ];
152 $this->fixtures['sched_activity_1day_r'] = [
6a488035
TO
153 'name' => 'One_Day_Phone_Call_Notice_R',
154 'title' => 'One Day Phone Call Notice R',
84a3e359 155 'limit_to' => 1,
6a488035
TO
156 'absolute_date' => NULL,
157 'body_html' => '<p>1-Day (repeating)</p>',
158 'body_text' => '1-Day (repeating)',
159 'end_action' => 'after',
160 'end_date' => 'activity_date_time',
161 'end_frequency_interval' => '2',
162 'end_frequency_unit' => 'day',
163 'entity_status' => '1',
164 'entity_value' => '2',
165 'group_id' => NULL,
166 'is_active' => '1',
167 'is_repeat' => '1',
168 'mapping_id' => '1',
169 'msg_template_id' => NULL,
170 'recipient' => '2',
171 'recipient_listing' => NULL,
172 'recipient_manual' => NULL,
173 'record_activity' => NULL,
174 'repetition_frequency_interval' => '6',
175 'repetition_frequency_unit' => 'hour',
176 'start_action_condition' => 'before',
177 'start_action_date' => 'activity_date_time',
178 'start_action_offset' => '1',
179 'start_action_unit' => 'day',
f8c3594b 180 'subject' => '1-Day (repeating) (about {activity.activity_type})',
9099cab3
CW
181 ];
182 $this->fixtures['sched_activity_1day_r_on_abs_date'] = [
dc6c330d 183 'name' => 'One_Day_Phone_Call_Notice_R',
184 'title' => 'One Day Phone Call Notice R',
185 'limit_to' => 1,
186 'absolute_date' => CRM_Utils_Date::processDate('20120614100000'),
187 'body_html' => '<p>1-Day (repeating)</p>',
188 'body_text' => '1-Day (repeating)',
189 'entity_status' => '1',
190 'entity_value' => '2',
191 'group_id' => NULL,
192 'is_active' => '1',
193 'is_repeat' => '1',
194 'mapping_id' => '1',
195 'msg_template_id' => NULL,
196 'recipient' => '2',
197 'recipient_listing' => NULL,
198 'recipient_manual' => NULL,
199 'record_activity' => NULL,
200 'repetition_frequency_interval' => '6',
201 'repetition_frequency_unit' => 'hour',
202 'end_action' => 'after',
203 'end_date' => 'activity_date_time',
204 'end_frequency_interval' => '2',
205 'end_frequency_unit' => 'day',
206 'start_action_condition' => '',
207 'start_action_date' => '',
208 'start_action_offset' => '',
209 'start_action_unit' => '',
210 'subject' => '1-Day (repeating) (about {activity.activity_type})',
9099cab3
CW
211 ];
212 $this->fixtures['sched_eventname_1day_on_abs_date'] = [
e08fae02
PH
213 'name' => 'sched_eventname_1day_on_abs_date',
214 'title' => 'sched_eventname_1day_on_abs_date',
215 'limit_to' => 1,
216 'absolute_date' => CRM_Utils_Date::processDate('20120614100000'),
217 'body_html' => '<p>sched_eventname_1day_on_abs_date</p>',
218 'body_text' => 'sched_eventname_1day_on_abs_date',
219 'entity_status' => '1',
220 'entity_value' => '2',
221 'group_id' => NULL,
222 'is_active' => '1',
223 'is_repeat' => '0',
224 'mapping_id' => '3',
225 'msg_template_id' => NULL,
226 'recipient' => '2',
227 'recipient_listing' => NULL,
228 'recipient_manual' => NULL,
229 'record_activity' => NULL,
230 'repetition_frequency_interval' => NULL,
231 'repetition_frequency_unit' => NULL,
232 'end_action' => NULL,
233 'end_date' => NULL,
234 'end_frequency_interval' => NULL,
235 'end_frequency_unit' => NULL,
236 'start_action_condition' => NULL,
237 'start_action_date' => NULL,
238 'start_action_offset' => NULL,
239 'start_action_unit' => NULL,
240 'subject' => 'sched_eventname_1day_on_abs_date',
9099cab3
CW
241 ];
242 $this->fixtures['sched_membership_join_2week'] = [
6a488035
TO
243 'name' => 'sched_membership_join_2week',
244 'title' => 'sched_membership_join_2week',
245 'absolute_date' => '',
246 'body_html' => '<p>body sched_membership_join_2week</p>',
247 'body_text' => 'body sched_membership_join_2week',
248 'end_action' => '',
249 'end_date' => '',
250 'end_frequency_interval' => '',
251 'end_frequency_unit' => '',
252 'entity_status' => '',
253 'entity_value' => '',
254 'group_id' => '',
255 'is_active' => 1,
256 'is_repeat' => '0',
257 'mapping_id' => 4,
258 'msg_template_id' => '',
259 'recipient' => '',
260 'recipient_listing' => '',
261 'recipient_manual' => '',
262 'record_activity' => 1,
263 'repetition_frequency_interval' => '',
264 'repetition_frequency_unit' => '',
265 'start_action_condition' => 'after',
266 'start_action_date' => 'membership_join_date',
267 'start_action_offset' => '2',
268 'start_action_unit' => 'week',
f8c3594b 269 'subject' => 'subject sched_membership_join_2week (joined {membership.join_date})',
9099cab3
CW
270 ];
271 $this->fixtures['sched_membership_start_1week'] = [
bb3ba83e
AH
272 'name' => 'sched_membership_start_1week',
273 'title' => 'sched_membership_start_1week',
274 'absolute_date' => '',
275 'body_html' => '<p>body sched_membership_start_1week</p>',
276 'body_text' => 'body sched_membership_start_1week',
277 'end_action' => '',
278 'end_date' => '',
279 'end_frequency_interval' => '',
280 'end_frequency_unit' => '',
281 'entity_status' => '',
282 'entity_value' => '',
283 'group_id' => '',
284 'is_active' => 1,
285 'is_repeat' => '0',
286 'mapping_id' => 4,
287 'msg_template_id' => '',
288 'recipient' => '',
289 'recipient_listing' => '',
290 'recipient_manual' => '',
291 'record_activity' => 1,
292 'repetition_frequency_interval' => '',
293 'repetition_frequency_unit' => '',
294 'start_action_condition' => 'after',
295 'start_action_date' => 'membership_start_date',
296 'start_action_offset' => '1',
297 'start_action_unit' => 'week',
298 'subject' => 'subject sched_membership_start_1week (joined {membership.start_date})',
9099cab3
CW
299 ];
300 $this->fixtures['sched_membership_end_2week'] = [
6a488035
TO
301 'name' => 'sched_membership_end_2week',
302 'title' => 'sched_membership_end_2week',
303 'absolute_date' => '',
304 'body_html' => '<p>body sched_membership_end_2week</p>',
305 'body_text' => 'body sched_membership_end_2week',
306 'end_action' => '',
307 'end_date' => '',
308 'end_frequency_interval' => '',
309 'end_frequency_unit' => '',
310 'entity_status' => '',
311 'entity_value' => '',
312 'group_id' => '',
313 'is_active' => 1,
314 'is_repeat' => '0',
315 'mapping_id' => 4,
316 'msg_template_id' => '',
317 'recipient' => '',
318 'recipient_listing' => '',
319 'recipient_manual' => '',
320 'record_activity' => 1,
321 'repetition_frequency_interval' => '',
322 'repetition_frequency_unit' => '',
323 'start_action_condition' => 'before',
324 'start_action_date' => 'membership_end_date',
325 'start_action_offset' => '2',
326 'start_action_unit' => 'week',
327 'subject' => 'subject sched_membership_end_2week',
9099cab3
CW
328 ];
329 $this->fixtures['sched_on_membership_end_date'] = [
d2868251 330 'name' => 'sched_on_membership_end_date',
331 'title' => 'sched_on_membership_end_date',
332 'body_html' => '<p>Your membership expired today</p>',
333 'body_text' => 'Your membership expired today',
334 'is_active' => 1,
335 'mapping_id' => 4,
336 'record_activity' => 1,
337 'start_action_condition' => 'after',
338 'start_action_date' => 'membership_end_date',
339 'start_action_offset' => '0',
340 'start_action_unit' => 'hour',
341 'subject' => 'subject send reminder on membership_end_date',
9099cab3
CW
342 ];
343 $this->fixtures['sched_after_1day_membership_end_date'] = [
d2868251 344 'name' => 'sched_after_1day_membership_end_date',
345 'title' => 'sched_after_1day_membership_end_date',
346 'body_html' => '<p>Your membership expired yesterday</p>',
347 'body_text' => 'Your membership expired yesterday',
348 'is_active' => 1,
349 'mapping_id' => 4,
350 'record_activity' => 1,
351 'start_action_condition' => 'after',
352 'start_action_date' => 'membership_end_date',
353 'start_action_offset' => '1',
354 'start_action_unit' => 'day',
355 'subject' => 'subject send reminder on membership_end_date',
9099cab3 356 ];
4b1efa1d 357
9099cab3 358 $this->fixtures['sched_membership_end_2month'] = [
4b1efa1d 359 'name' => 'sched_membership_end_2month',
360 'title' => 'sched_membership_end_2month',
361 'absolute_date' => '',
362 'body_html' => '<p>body sched_membership_end_2month</p>',
363 'body_text' => 'body sched_membership_end_2month',
364 'end_action' => '',
365 'end_date' => '',
366 'end_frequency_interval' => '',
367 'end_frequency_unit' => '',
368 'entity_status' => '',
369 'entity_value' => '',
370 'group_id' => '',
371 'is_active' => 1,
372 'is_repeat' => '0',
373 'mapping_id' => 4,
374 'msg_template_id' => '',
375 'recipient' => '',
376 'recipient_listing' => '',
377 'recipient_manual' => '',
378 'record_activity' => 1,
379 'repetition_frequency_interval' => '',
380 'repetition_frequency_unit' => '',
381 'start_action_condition' => 'after',
382 'start_action_date' => 'membership_end_date',
383 'start_action_offset' => '2',
384 'start_action_unit' => 'month',
385 'subject' => 'subject sched_membership_end_2month',
9099cab3 386 ];
4b1efa1d 387
9099cab3 388 $this->fixtures['sched_membership_absolute_date'] = [
e08fae02
PH
389 'name' => 'sched_membership_absolute_date',
390 'title' => 'sched_membership_absolute_date',
391 'absolute_date' => CRM_Utils_Date::processDate('20120614100000'),
392 'body_html' => '<p>body sched_membership_absolute_date</p>',
393 'body_text' => 'body sched_membership_absolute_date',
394 'end_action' => '',
395 'end_date' => '',
396 'end_frequency_interval' => '',
397 'end_frequency_unit' => '',
398 'entity_status' => '',
399 'entity_value' => '',
400 'group_id' => '',
401 'is_active' => 1,
402 'is_repeat' => '0',
403 'mapping_id' => 4,
404 'msg_template_id' => '',
405 'recipient' => '',
406 'recipient_listing' => '',
407 'recipient_manual' => '',
408 'record_activity' => 1,
409 'repetition_frequency_interval' => '',
410 'repetition_frequency_unit' => '',
411 'start_action_condition' => '',
412 'start_action_date' => '',
413 'start_action_offset' => '',
414 'start_action_unit' => '',
415 'subject' => 'subject sched_membership_absolute_date',
9099cab3 416 ];
e08fae02 417
9099cab3 418 $this->fixtures['sched_contact_bday_yesterday'] = [
43030baf
AH
419 'name' => 'sched_contact_bday_yesterday',
420 'title' => 'sched_contact_bday_yesterday',
421 'absolute_date' => '',
422 'body_html' => '<p>you look like you were born yesterday!</p>',
423 'body_text' => 'you look like you were born yesterday!',
424 'end_action' => '',
425 'end_date' => '',
426 'end_frequency_interval' => '',
427 'end_frequency_unit' => '',
428 'entity_status' => 1,
429 'entity_value' => 'birth_date',
430 'group_id' => '',
431 'is_active' => 1,
432 'is_repeat' => '0',
433 'mapping_id' => 6,
434 'msg_template_id' => '',
435 'recipient' => '',
436 'recipient_listing' => '',
437 'recipient_manual' => '',
438 'record_activity' => 1,
439 'repetition_frequency_interval' => '',
440 'repetition_frequency_unit' => '',
441 'start_action_condition' => 'after',
442 'start_action_date' => 'date_field',
443 'start_action_offset' => '1',
444 'start_action_unit' => 'day',
445 'subject' => 'subject sched_contact_bday_yesterday',
9099cab3 446 ];
43030baf 447
9099cab3 448 $this->fixtures['sched_contact_bday_anniv'] = [
43030baf
AH
449 'name' => 'sched_contact_bday_anniv',
450 'title' => 'sched_contact_bday_anniv',
451 'absolute_date' => '',
452 'body_html' => '<p>happy birthday!</p>',
453 'body_text' => 'happy birthday!',
454 'end_action' => '',
455 'end_date' => '',
456 'end_frequency_interval' => '',
457 'end_frequency_unit' => '',
458 'entity_status' => 2,
459 'entity_value' => 'birth_date',
460 'group_id' => '',
461 'is_active' => 1,
462 'is_repeat' => '0',
463 'mapping_id' => 6,
464 'msg_template_id' => '',
465 'recipient' => '',
466 'recipient_listing' => '',
467 'recipient_manual' => '',
468 'record_activity' => 1,
469 'repetition_frequency_interval' => '',
470 'repetition_frequency_unit' => '',
471 'start_action_condition' => 'before',
472 'start_action_date' => 'date_field',
473 'start_action_offset' => '1',
474 'start_action_unit' => 'day',
475 'subject' => 'subject sched_contact_bday_anniv',
9099cab3 476 ];
43030baf 477
9099cab3 478 $this->fixtures['sched_contact_grad_tomorrow'] = [
43030baf
AH
479 'name' => 'sched_contact_grad_tomorrow',
480 'title' => 'sched_contact_grad_tomorrow',
481 'absolute_date' => '',
482 'body_html' => '<p>congratulations on your graduation!</p>',
483 'body_text' => 'congratulations on your graduation!',
484 'end_action' => '',
485 'end_date' => '',
486 'end_frequency_interval' => '',
487 'end_frequency_unit' => '',
488 'entity_status' => 1,
489 'group_id' => '',
490 'is_active' => 1,
491 'is_repeat' => '0',
492 'mapping_id' => 6,
493 'msg_template_id' => '',
494 'recipient' => '',
495 'recipient_listing' => '',
496 'recipient_manual' => '',
497 'record_activity' => 1,
498 'repetition_frequency_interval' => '',
499 'repetition_frequency_unit' => '',
500 'start_action_condition' => 'before',
501 'start_action_date' => 'date_field',
502 'start_action_offset' => '1',
503 'start_action_unit' => 'day',
504 'subject' => 'subject sched_contact_grad_tomorrow',
9099cab3 505 ];
43030baf 506
9099cab3 507 $this->fixtures['sched_contact_grad_anniv'] = [
43030baf
AH
508 'name' => 'sched_contact_grad_anniv',
509 'title' => 'sched_contact_grad_anniv',
510 'absolute_date' => '',
511 'body_html' => '<p>dear alum, please send us money.</p>',
512 'body_text' => 'dear alum, please send us money.',
513 'end_action' => '',
514 'end_date' => '',
515 'end_frequency_interval' => '',
516 'end_frequency_unit' => '',
517 'entity_status' => 2,
518 'group_id' => '',
519 'is_active' => 1,
520 'is_repeat' => '0',
521 'mapping_id' => 6,
522 'msg_template_id' => '',
523 'recipient' => '',
524 'recipient_listing' => '',
525 'recipient_manual' => '',
526 'record_activity' => 1,
527 'repetition_frequency_interval' => '',
528 'repetition_frequency_unit' => '',
529 'start_action_condition' => 'after',
530 'start_action_date' => 'date_field',
531 'start_action_offset' => '1',
532 'start_action_unit' => 'week',
533 'subject' => 'subject sched_contact_grad_anniv',
9099cab3 534 ];
4aff0253 535
9099cab3 536 $this->fixtures['sched_contact_created_yesterday'] = [
4aff0253
AH
537 'name' => 'sched_contact_created_yesterday',
538 'title' => 'sched_contact_created_yesterday',
539 'absolute_date' => '',
540 'body_html' => '<p>Your contact was created yesterday</p>',
541 'body_text' => 'Your contact was created yesterday!',
542 'end_action' => '',
543 'end_date' => '',
544 'end_frequency_interval' => '',
545 'end_frequency_unit' => '',
546 'entity_status' => 1,
547 'entity_value' => 'created_date',
548 'group_id' => '',
549 'is_active' => 1,
550 'is_repeat' => '0',
551 'mapping_id' => 6,
552 'msg_template_id' => '',
553 'recipient' => '',
554 'recipient_listing' => '',
555 'recipient_manual' => '',
556 'record_activity' => 1,
557 'repetition_frequency_interval' => '',
558 'repetition_frequency_unit' => '',
559 'start_action_condition' => 'after',
560 'start_action_date' => 'date_field',
561 'start_action_offset' => '1',
562 'start_action_unit' => 'day',
563 'subject' => 'subject sched_contact_created_yesterday',
9099cab3 564 ];
4aff0253 565
9099cab3 566 $this->fixtures['sched_contact_mod_anniv'] = [
4aff0253
AH
567 'name' => 'sched_contact_mod_anniv',
568 'title' => 'sched_contact_mod_anniv',
569 'absolute_date' => '',
570 'body_html' => '<p>You last updated your data last year</p>',
571 'body_text' => 'Go update your stuff!',
572 'end_action' => '',
573 'end_date' => '',
574 'end_frequency_interval' => '',
575 'end_frequency_unit' => '',
576 'entity_status' => 2,
577 'entity_value' => 'modified_date',
578 'group_id' => '',
579 'is_active' => 1,
580 'is_repeat' => '0',
581 'mapping_id' => 6,
582 'msg_template_id' => '',
583 'recipient' => '',
584 'recipient_listing' => '',
585 'recipient_manual' => '',
586 'record_activity' => 1,
587 'repetition_frequency_interval' => '',
588 'repetition_frequency_unit' => '',
589 'start_action_condition' => 'before',
590 'start_action_date' => 'date_field',
591 'start_action_offset' => '1',
592 'start_action_unit' => 'day',
593 'subject' => 'subject sched_contact_mod_anniv',
9099cab3 594 ];
4aff0253 595
9099cab3 596 $this->fixtures['sched_eventtype_start_1week_before'] = [
d3eae6ea
TO
597 'name' => 'sched_eventtype_start_1week_before',
598 'title' => 'sched_eventtype_start_1week_before',
599 'absolute_date' => '',
600 'body_html' => '<p>body sched_eventtype_start_1week_before ({event.title})</p>',
601 'body_text' => 'body sched_eventtype_start_1week_before ({event.title})',
602 'end_action' => '',
603 'end_date' => '',
604 'end_frequency_interval' => '',
605 'end_frequency_unit' => '',
39b959db
SL
606 // participant status id
607 'entity_status' => '',
608 // event type id
609 'entity_value' => '',
d3eae6ea
TO
610 'group_id' => '',
611 'is_active' => 1,
612 'is_repeat' => '0',
39b959db
SL
613 // event type
614 'mapping_id' => 2,
d3eae6ea
TO
615 'msg_template_id' => '',
616 'recipient' => '',
617 'recipient_listing' => '',
618 'recipient_manual' => '',
619 'record_activity' => 1,
620 'repetition_frequency_interval' => '',
621 'repetition_frequency_unit' => '',
622 'start_action_condition' => 'before',
623 'start_action_date' => 'event_start_date',
624 'start_action_offset' => '1',
625 'start_action_unit' => 'week',
626 'subject' => 'subject sched_eventtype_start_1week_before ({event.title})',
9099cab3
CW
627 ];
628 $this->fixtures['sched_eventtype_end_2month_repeat_twice_2_weeks'] = [
d3eae6ea
TO
629 'name' => 'sched_eventtype_end_2month_repeat_twice_2_weeks',
630 'title' => 'sched_eventtype_end_2month_repeat_twice_2_weeks',
631 'absolute_date' => '',
632 'body_html' => '<p>body sched_eventtype_end_2month_repeat_twice_2_weeks {event.title}</p>',
633 'body_text' => 'body sched_eventtype_end_2month_repeat_twice_2_weeks {event.title}',
634 'end_action' => 'after',
635 'end_date' => 'event_end_date',
636 'end_frequency_interval' => '3',
637 'end_frequency_unit' => 'month',
39b959db
SL
638 // participant status id
639 'entity_status' => '',
640 // event type id
641 'entity_value' => '',
d3eae6ea
TO
642 'group_id' => '',
643 'is_active' => 1,
644 'is_repeat' => '1',
39b959db
SL
645 // event type
646 'mapping_id' => 2,
d3eae6ea
TO
647 'msg_template_id' => '',
648 'recipient' => '',
649 'recipient_listing' => '',
650 'recipient_manual' => '',
651 'record_activity' => 1,
652 'repetition_frequency_interval' => '2',
653 'repetition_frequency_unit' => 'week',
654 'start_action_condition' => 'after',
655 'start_action_date' => 'event_end_date',
656 'start_action_offset' => '2',
657 'start_action_unit' => 'month',
658 'subject' => 'subject sched_eventtype_end_2month_repeat_twice_2_weeks {event.title}',
9099cab3 659 ];
d3eae6ea 660
9099cab3 661 $this->fixtures['sched_membership_end_2month_repeat_twice_4_weeks'] = [
861d11c4
DG
662 'name' => 'sched_membership_end_2month',
663 'title' => 'sched_membership_end_2month',
664 'absolute_date' => '',
665 'body_html' => '<p>body sched_membership_end_2month</p>',
666 'body_text' => 'body sched_membership_end_2month',
667 'end_action' => '',
5c4d6559 668 'end_date' => 'membership_end_date',
861d11c4
DG
669 'end_frequency_interval' => '4',
670 'end_frequency_unit' => 'month',
671 'entity_status' => '',
672 'entity_value' => '',
673 'group_id' => '',
674 'is_active' => 1,
675 'is_repeat' => '1',
676 'mapping_id' => 4,
677 'msg_template_id' => '',
678 'recipient' => '',
679 'recipient_listing' => '',
680 'recipient_manual' => '',
681 'record_activity' => 1,
682 'repetition_frequency_interval' => '4',
683 'repetition_frequency_unit' => 'week',
684 'start_action_condition' => 'after',
685 'start_action_date' => 'membership_end_date',
686 'start_action_offset' => '2',
687 'start_action_unit' => 'month',
688 'subject' => 'subject sched_membership_end_2month',
9099cab3
CW
689 ];
690 $this->fixtures['sched_membership_end_limit_to_none'] = [
baa85770
EM
691 'name' => 'limit to none',
692 'title' => 'limit to none',
693 'absolute_date' => '',
694 'body_html' => '<p>body sched_membership_end_2month</p>',
695 'body_text' => 'body sched_membership_end_2month',
696 'end_action' => '',
697 'end_date' => '',
698 'end_frequency_interval' => '4',
699 'end_frequency_unit' => 'month',
700 'entity_status' => '',
701 'entity_value' => '',
702 'limit_to' => 0,
703 'group_id' => '',
704 'is_active' => 1,
705 'is_repeat' => '1',
706 'mapping_id' => 4,
707 'msg_template_id' => '',
708 'recipient' => '',
709 'recipient_listing' => '',
710 'recipient_manual' => '',
711 'record_activity' => 1,
712 'repetition_frequency_interval' => '4',
713 'repetition_frequency_unit' => 'week',
714 'start_action_condition' => 'after',
715 'start_action_date' => 'membership_end_date',
716 'start_action_offset' => '2',
717 'start_action_unit' => 'month',
718 'subject' => 'limit to none',
9099cab3
CW
719 ];
720 $this->fixtures['sched_on_membership_end_date_repeat_interval'] = [
52f09320
PH
721 'name' => 'sched_on_membership_end_date',
722 'title' => 'sched_on_membership_end_date',
723 'body_html' => '<p>Your membership expired 1 unit ago</p>',
724 'body_text' => 'Your membership expired 1 unit ago',
725 'end_frequency_interval' => 10,
726 'end_frequency_unit' => 'year',
727 'is_active' => 1,
728 'is_repeat' => TRUE,
729 'mapping_id' => 4,
730 'record_activity' => 1,
731 'start_action_condition' => 'after',
732 'start_action_date' => 'membership_end_date',
733 'start_action_offset' => '0',
734 'start_action_unit' => 'hour',
735 'subject' => 'subject send reminder every unit after membership_end_date',
9099cab3 736 ];
52f09320 737
9099cab3 738 $customGroup = $this->callAPISuccess('CustomGroup', 'create', [
2273ddcb 739 'title' => ts('Test Contact Custom group'),
740 'name' => 'test_contact_cg',
741 'extends' => 'Contact',
742 'domain_id' => CRM_Core_Config::domainID(),
743 'is_active' => 1,
744 'collapse_adv_display' => 0,
745 'collapse_display' => 0,
9099cab3
CW
746 ]);
747 $customField = $this->callAPISuccess('CustomField', 'create', [
2273ddcb 748 'label' => 'Test Text',
749 'data_type' => 'String',
750 'html_type' => 'Text',
751 'custom_group_id' => $customGroup['id'],
9099cab3
CW
752 ]);
753 $this->fixtures['contact_custom_token'] = [
2273ddcb 754 'id' => $customField['id'],
755 'token' => sprintf('{contact.custom_%s}', $customField['id']),
756 'name' => sprintf('custom_%s', $customField['id']),
757 'value' => 'text ' . substr(sha1(rand()), 0, 7),
9099cab3 758 ];
2273ddcb 759
6a488035 760 $this->_setUp();
6a488035
TO
761 }
762
763 /**
764 * Tears down the fixture, for example, closes a network connection.
92c99a4a 765 *
6a488035 766 * This method is called after a test is executed.
34662dda 767 *
768 * @throws \CRM_Core_Exception
6a488035 769 */
00be9182 770 public function tearDown() {
6a488035 771 parent::tearDown();
6a488035
TO
772 $this->mut->clearMessages();
773 $this->mut->stop();
774 unset($this->mut);
9099cab3 775 $this->quickCleanup([
92c99a4a
EM
776 'civicrm_action_schedule',
777 'civicrm_action_log',
778 'civicrm_membership',
d3eae6ea
TO
779 'civicrm_participant',
780 'civicrm_event',
92c99a4a 781 'civicrm_email',
9099cab3
CW
782 ]);
783 $this->callAPISuccess('CustomField', 'delete', ['id' => $this->fixtures['contact_custom_token']['id']]);
784 $this->callAPISuccess('CustomGroup', 'delete', [
2273ddcb 785 'id' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', 'test_contact_cg', 'id', 'name'),
9099cab3 786 ]);
6a488035
TO
787 $this->_tearDown();
788 }
789
34662dda 790 /**
791 * Get mailer examples.
792 *
793 * @return array
794 */
43ceab3f 795 public function mailerExamples() {
9099cab3 796 $cases = [];
43ceab3f 797
bba4f3f6 798 // Some tokens - short as subject has 128char limit in DB.
9099cab3 799 $someTokensTmpl = implode(';;', [
39b959db
SL
800 // basic contact token
801 '{contact.display_name}',
802 // funny legacy contact token
803 '{contact.gender}',
804 // funny legacy contact token
805 '{contact.gender_id}',
806 // domain token
807 '{domain.name}',
808 // action-scheduler token
809 '{activity.activity_type}',
9099cab3 810 ]);
bba4f3f6 811 // Further tokens can be tested in the body text/html.
9099cab3 812 $manyTokensTmpl = implode(';;', [
bba4f3f6
CB
813 $someTokensTmpl,
814 '{contact.email_greeting}',
34662dda 815 $this->fixtures['contact_custom_token']['token'],
9099cab3 816 ]);
ccdf6bd5
TO
817 // Note: The behavior of domain-tokens on a scheduled reminder is undefined. All we
818 // can really do is check that it has something.
bba4f3f6 819 $someTokensExpected = 'Churmondleia Ōtākou;;Female;;Female;;[a-zA-Z0-9 ]+;;Phone Call';
34662dda 820 $manyTokensExpected = sprintf('%s;;Dear Churmondleia;;%s', $someTokensExpected, $this->fixtures['contact_custom_token']['value']);
43ceab3f 821
bba4f3f6 822 // In this example, we use a lot of tokens cutting across multiple components.
9099cab3 823 $cases[0] = [
43ceab3f 824 // Schedule definition.
9099cab3 825 [
bba4f3f6 826 'subject' => "subj $someTokensTmpl",
43ceab3f
TO
827 'body_html' => "html $manyTokensTmpl",
828 'body_text' => "text $manyTokensTmpl",
9099cab3 829 ],
43ceab3f 830 // Assertions (regex).
9099cab3 831 [
34662dda 832 'from_name' => '/^FIXME$/',
833 'from_email' => '/^info@EXAMPLE.ORG$/',
bba4f3f6 834 'subject' => "/^subj $someTokensExpected\$/",
43ceab3f
TO
835 'body_html' => "/^html $manyTokensExpected\$/",
836 'body_text' => "/^text $manyTokensExpected\$/",
9099cab3
CW
837 ],
838 ];
43ceab3f
TO
839
840 // In this example, we customize the from address.
9099cab3 841 $cases[1] = [
43ceab3f 842 // Schedule definition.
9099cab3 843 [
43ceab3f
TO
844 'from_name' => 'Bob',
845 'from_email' => 'bob@example.org',
9099cab3 846 ],
43ceab3f 847 // Assertions (regex).
9099cab3 848 [
34662dda 849 'from_name' => '/^Bob$/',
850 'from_email' => '/^bob@example.org$/',
9099cab3
CW
851 ],
852 ];
43ceab3f
TO
853
854 // In this example, we autoconvert HTML to text
9099cab3 855 $cases[2] = [
43ceab3f 856 // Schedule definition.
9099cab3 857 [
43ceab3f
TO
858 'body_html' => '<p>Hello &amp; stuff.</p>',
859 'body_text' => '',
9099cab3 860 ],
43ceab3f 861 // Assertions (regex).
9099cab3 862 [
43ceab3f
TO
863 'body_html' => '/^' . preg_quote('<p>Hello &amp; stuff.</p>', '/') . '/',
864 'body_text' => '/^' . preg_quote('Hello & stuff.', '/') . '/',
9099cab3
CW
865 ],
866 ];
43ceab3f
TO
867
868 // In this example, we autoconvert HTML to text
9099cab3 869 $cases[3] = [
43ceab3f 870 // Schedule definition.
9099cab3 871 [
43ceab3f
TO
872 'body_html' => '',
873 'body_text' => 'Hello world',
9099cab3 874 ],
43ceab3f 875 // Assertions (regex).
9099cab3 876 [
43ceab3f
TO
877 'body_html' => '/^--UNDEFINED--$/',
878 'body_text' => '/^Hello world$/',
9099cab3
CW
879 ],
880 ];
43ceab3f
TO
881
882 return $cases;
883 }
884
885 /**
886 * This generates a single mailing through the scheduled-reminder
887 * system (using an activity-reminder as a baseline) and
888 * checks that the resulting message satisfies various
889 * regular expressions.
890 *
891 * @param array $schedule
892 * Values to set/override in the schedule.
893 * Ex: array('subject' => 'Hello, {contact.first_name}!').
894 * @param array $patterns
895 * A list of regexes to compare with the actual email.
896 * Ex: array('subject' => '/^Hello, Alice!/').
897 * Keys: subject, body_text, body_html, from_name, from_email.
34662dda 898 *
43ceab3f 899 * @dataProvider mailerExamples
34662dda 900 *
901 * @throws \CRM_Core_Exception
43ceab3f
TO
902 */
903 public function testMailer($schedule, $patterns) {
904 $actionSchedule = array_merge($this->fixtures['sched_activity_1day'], $schedule);
905 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 906 $this->assertInternalType('numeric', $actionScheduleDao->id);
43ceab3f
TO
907
908 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
34662dda 909 $this->assertInternalType('numeric', $activity->id);
2273ddcb 910 $contact = $this->callAPISuccess('contact', 'create', array_merge(
911 $this->fixtures['contact'],
9099cab3 912 [
2273ddcb 913 $this->fixtures['contact_custom_token']['name'] => $this->fixtures['contact_custom_token']['value'],
9099cab3 914 ]
2273ddcb 915 ));
43ceab3f
TO
916 $activity->save();
917
918 $source['contact_id'] = $contact['id'];
919 $source['activity_id'] = $activity->id;
920 $source['record_type_id'] = 2;
921 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
922 $activityContact->save();
923
924 CRM_Utils_Time::setTime('2012-06-14 15:00:00');
34662dda 925 $this->callAPISuccess('job', 'send_reminder');
9099cab3 926 $this->mut->assertRecipients([['test-member@example.com']]);
43ceab3f
TO
927 foreach ($this->mut->getAllMessages('ezc') as $message) {
928 /** @var ezcMail $message */
929
9099cab3 930 $messageArray = [];
43ceab3f
TO
931 $messageArray['subject'] = $message->subject;
932 $messageArray['from_name'] = $message->from->name;
933 $messageArray['from_email'] = $message->from->email;
934 $messageArray['body_text'] = '--UNDEFINED--';
935 $messageArray['body_html'] = '--UNDEFINED--';
936
937 foreach ($message->fetchParts() as $part) {
938 /** @var ezcMailText ezcMailText */
34662dda 939 if ($part instanceof ezcMailText && $part->subType === 'html') {
43ceab3f
TO
940 $messageArray['body_html'] = $part->text;
941 }
34662dda 942 if ($part instanceof ezcMailText && $part->subType === 'plain') {
43ceab3f
TO
943 $messageArray['body_text'] = $part->text;
944 }
945 }
946
947 foreach ($patterns as $field => $pattern) {
948 $this->assertRegExp($pattern, $messageArray[$field],
9099cab3 949 "Check that '$field'' matches regex. " . print_r(['expected' => $patterns, 'actual' => $messageArray], 1));
43ceab3f
TO
950 }
951 }
952 $this->mut->clearMessages();
43ceab3f
TO
953 }
954
34662dda 955 /**
956 * Test calculated activity schedule.
957 *
958 * @throws \CRM_Core_Exception
959 */
92c99a4a 960 public function testActivityDateTimeMatchNonRepeatableSchedule() {
34662dda 961 $this->createScheduleFromFixtures('sched_activity_1day');
6a488035
TO
962
963 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
34662dda 964 $this->assertInternalType('numeric', $activity->id);
6c6e6187 965 $contact = $this->callAPISuccess('contact', 'create', $this->fixtures['contact']);
34662dda 966 $activity->subject = 'Test subject for Phonecall';
6a488035
TO
967 $activity->save();
968
4f20f356 969 $source['contact_id'] = $contact['id'];
970 $source['activity_id'] = $activity->id;
971 $source['record_type_id'] = 2;
972 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
973 $activityContact->save();
974
9099cab3
CW
975 $this->assertCronRuns([
976 [
567b2076 977 // Before the 24-hour mark, no email
6a488035 978 'time' => '2012-06-14 04:00:00',
9099cab3
CW
979 'recipients' => [],
980 'subjects' => [],
981 ],
982 [
567b2076 983 // After the 24-hour mark, an email
6a488035 984 'time' => '2012-06-14 15:00:00',
9099cab3
CW
985 'recipients' => [['test-member@example.com']],
986 'subjects' => ['1-Day (non-repeating) (about Phone Call)'],
987 ],
988 [
567b2076 989 // Run cron again; message already sent
6a488035 990 'time' => '',
9099cab3
CW
991 'recipients' => [],
992 ],
993 ]);
d19632b1
JP
994 $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name');
995 $activityDAO = new CRM_Activity_DAO_Activity();
996 $activityDAO->source_record_id = $activity->id;
997 $activityDAO->activity_type_id = array_search('Reminder Sent', $activityTypes);
998 $activityDAO->find();
999 while ($activityDAO->fetch()) {
1000 $this->assertContains($activity->subject, $activityDAO->details);
1001 }
6a488035
TO
1002 }
1003
34662dda 1004 /**
1005 * Test schedule creation on repeatable schedule.
1006 *
1007 * @throws \CRM_Core_Exception
1008 */
92c99a4a 1009 public function testActivityDateTimeMatchRepeatableSchedule() {
34662dda 1010 $this->createScheduleFromFixtures('sched_activity_1day_r');
6a488035
TO
1011
1012 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
1013 $this->assertTrue(is_numeric($activity->id));
6c6e6187 1014 $contact = $this->callAPISuccess('contact', 'create', $this->fixtures['contact']);
6a488035
TO
1015 $activity->save();
1016
4f20f356 1017 $source['contact_id'] = $contact['id'];
1018 $source['activity_id'] = $activity->id;
6c6e6187 1019 $source['record_type_id'] = 2;
4f20f356 1020 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
1021 $activityContact->save();
1022
9099cab3
CW
1023 $this->assertCronRuns([
1024 [
567b2076 1025 // Before the 24-hour mark, no email
6a488035 1026 'time' => '012-06-14 04:00:00',
9099cab3
CW
1027 'recipients' => [],
1028 'subjects' => [],
1029 ],
1030 [
567b2076 1031 // After the 24-hour mark, an email
6a488035 1032 'time' => '2012-06-14 15:00:00',
9099cab3
CW
1033 'recipients' => [['test-member@example.com']],
1034 'subjects' => ['1-Day (repeating) (about Phone Call)'],
1035 ],
1036 [
567b2076 1037 // Run cron 4 hours later; first message already sent
6a488035 1038 'time' => '2012-06-14 20:00:00',
9099cab3
CW
1039 'recipients' => [],
1040 'subjects' => [],
1041 ],
1042 [
567b2076 1043 // Run cron 6 hours later; send second message.
6a488035 1044 'time' => '2012-06-14 21:00:01',
9099cab3
CW
1045 'recipients' => [['test-member@example.com']],
1046 'subjects' => ['1-Day (repeating) (about Phone Call)'],
1047 ],
1048 ]);
6a488035
TO
1049 }
1050
34662dda 1051 /**
1052 * @throws \CRM_Core_Exception
1053 */
dc6c330d 1054 public function testActivityDateTimeMatchRepeatableScheduleOnAbsDate() {
34662dda 1055 $this->createScheduleFromFixtures('sched_activity_1day_r_on_abs_date');
dc6c330d 1056
1057 $activity = $this->createTestObject('CRM_Activity_DAO_Activity', $this->fixtures['phonecall']);
34662dda 1058 $this->assertInternalType('numeric', $activity->id);
dc6c330d 1059 $contact = $this->callAPISuccess('contact', 'create', $this->fixtures['contact']);
1060 $activity->save();
1061
1062 $source['contact_id'] = $contact['id'];
1063 $source['activity_id'] = $activity->id;
1064 $source['record_type_id'] = 2;
1065 $activityContact = $this->createTestObject('CRM_Activity_DAO_ActivityContact', $source);
1066 $activityContact->save();
1067
9099cab3
CW
1068 $this->assertCronRuns([
1069 [
dc6c330d 1070 // Before the 24-hour mark, no email
1071 'time' => '2012-06-13 04:00:00',
9099cab3
CW
1072 'recipients' => [],
1073 'subjects' => [],
1074 ],
1075 [
dc6c330d 1076 // On absolute date set on 2012-06-14
1077 'time' => '2012-06-14 00:00:00',
9099cab3
CW
1078 'recipients' => [['test-member@example.com']],
1079 'subjects' => ['1-Day (repeating) (about Phone Call)'],
1080 ],
1081 [
dc6c330d 1082 // Run cron 4 hours later; first message already sent
1083 'time' => '2012-06-14 04:00:00',
9099cab3
CW
1084 'recipients' => [],
1085 'subjects' => [],
1086 ],
1087 [
dc6c330d 1088 // Run cron 6 hours later; send second message.
1089 'time' => '2012-06-14 06:00:01',
9099cab3
CW
1090 'recipients' => [['test-member@example.com']],
1091 'subjects' => ['1-Day (repeating) (about Phone Call)'],
1092 ],
1093 ]);
dc6c330d 1094 }
1095
34662dda 1096 /**
1097 * Test event with only an absolute date.
1098 *
1099 * @throws \CRM_Core_Exception
1100 */
e08fae02 1101 public function testEventNameWithAbsoluteDateAndNothingElse() {
9099cab3
CW
1102 $participant = $this->createTestObject('CRM_Event_DAO_Participant', array_merge($this->fixtures['participant'], ['status_id' => 1]));
1103 $this->callAPISuccess('Email', 'create', [
e08fae02
PH
1104 'contact_id' => $participant->contact_id,
1105 'email' => 'test-event@example.com',
9099cab3
CW
1106 ]);
1107 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $participant->contact_id]));
e08fae02
PH
1108
1109 $actionSchedule = $this->fixtures['sched_eventname_1day_on_abs_date'];
1110 $actionSchedule['entity_value'] = $participant->event_id;
1111 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
1112
9099cab3
CW
1113 $this->assertCronRuns([
1114 [
e08fae02
PH
1115 // Before the 24-hour mark, no email
1116 'time' => '2012-06-13 04:00:00',
9099cab3
CW
1117 'recipients' => [],
1118 'subjects' => [],
1119 ],
1120 [
e08fae02
PH
1121 // On absolute date set on 2012-06-14
1122 'time' => '2012-06-14 00:00:00',
9099cab3
CW
1123 'recipients' => [['test-event@example.com']],
1124 'subjects' => ['sched_eventname_1day_on_abs_date'],
1125 ],
1126 [
e08fae02
PH
1127 // Run cron 4 hours later; first message already sent
1128 'time' => '2012-06-14 04:00:00',
9099cab3
CW
1129 'recipients' => [],
1130 'subjects' => [],
1131 ],
1132 ]);
e08fae02
PH
1133 }
1134
6a488035
TO
1135 /**
1136 * For contacts/activities which don't match the schedule filter,
1137 * an email should *not* be sent.
1138 */
1139 // TODO // function testActivityDateTime_NonMatch() { }
1140
1141 /**
76ea51c7 1142 * For contacts/members which match schedule based on join/start date,
6a488035 1143 * an email should be sent.
34662dda 1144 *
1145 * @throws \CRM_Core_Exception
6a488035 1146 */
76ea51c7 1147 public function testMembershipDateMatch() {
9099cab3 1148 $membership = $this->createTestObject('CRM_Member_DAO_Membership', array_merge($this->fixtures['rolling_membership'], ['status_id' => 1]));
34662dda 1149 $this->assertInternalType('numeric', $membership->id);
1150 $this->callAPISuccess('Email', 'create', [
bb3ba83e
AH
1151 'contact_id' => $membership->contact_id,
1152 'email' => 'test-member@example.com',
1153 'location_type_id' => 1,
1154 'is_primary' => 1,
9099cab3 1155 ]);
6a488035 1156
9099cab3 1157 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
bb3ba83e
AH
1158 $actionSchedule = $this->fixtures['sched_membership_join_2week'];
1159 $actionSchedule['entity_value'] = $membership->membership_type_id;
1160 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 1161 $this->assertInternalType('numeric', $actionScheduleDao->id);
6a488035 1162
bb3ba83e 1163 // start_date=2012-03-15 ; schedule is 2 weeks after join_date
9099cab3
CW
1164 $this->assertCronRuns([
1165 [
bb3ba83e
AH
1166 // Before the 2-week mark, no email.
1167 'time' => '2012-03-28 01:00:00',
9099cab3
CW
1168 'recipients' => [],
1169 'subjects' => [],
1170 ],
1171 [
bb3ba83e
AH
1172 // After the 2-week mark, send an email.
1173 'time' => '2012-03-29 01:00:00',
9099cab3
CW
1174 'recipients' => [['test-member@example.com']],
1175 'subjects' => ['subject sched_membership_join_2week (joined March 15th, 2012)'],
1176 ],
1177 ]);
bb3ba83e
AH
1178
1179 $actionSchedule = $this->fixtures['sched_membership_start_1week'];
1180 $actionSchedule['entity_value'] = $membership->membership_type_id;
1181 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 1182 $this->assertInternalType('numeric', $actionScheduleDao->id);
bb3ba83e
AH
1183
1184 // start_date=2012-03-15 ; schedule is 1 weeks after start_date
9099cab3
CW
1185 $this->assertCronRuns([
1186 [
bb3ba83e
AH
1187 // Before the 2-week mark, no email.
1188 'time' => '2012-03-21 01:00:00',
9099cab3
CW
1189 'recipients' => [],
1190 'subjects' => [],
1191 ],
1192 [
bb3ba83e
AH
1193 // After the 2-week mark, send an email.
1194 'time' => '2012-03-22 01:00:00',
9099cab3
CW
1195 'recipients' => [['test-member@example.com']],
1196 'subjects' => ['subject sched_membership_start_1week (joined March 15th, 2012)'],
1197 ],
1198 ]);
6a488035
TO
1199 }
1200
cc949606 1201 /**
1202 * CRM-21675: Support parent and smart group in 'Limit to' field
34662dda 1203 *
1204 * @throws \CRM_Core_Exception
cc949606 1205 */
1206 public function testScheduleReminderWithParentGroup() {
1207 // Contact A with birth-date at '07-07-2005' and gender - Male, later got added in smart group
34662dda 1208 $this->individualCreate(['birth_date' => '20050707', 'gender_id' => 1, 'email' => 'abc@test.com']);
cc949606 1209 // Contact B with birth-date at '07-07-2005', later got added in regular group
9099cab3 1210 $contactID2 = $this->individualCreate(['birth_date' => '20050707', 'email' => 'def@test.com'], 1);
cc949606 1211 // Contact C with birth-date at '07-07-2005', but not included in any group
34662dda 1212 $this->individualCreate(['birth_date' => '20050707', 'email' => 'ghi@test.com'], 2);
cc949606 1213
1214 // create regular group and add Contact B to it
1215 $groupID = $this->groupCreate();
9099cab3 1216 $this->callAPISuccess('GroupContact', 'Create', [
cc949606 1217 'group_id' => $groupID,
1218 'contact_id' => $contactID2,
9099cab3 1219 ]);
cc949606 1220
1221 // create smart group which will contain all Male contacts
fe38e286 1222 $smartGroupParams = ['form_values' => ['gender_id' => 1]];
cc949606 1223 $smartGroupID = $this->smartGroupCreate(
1224 $smartGroupParams,
9099cab3 1225 [
cc949606 1226 'name' => 'new_smart_group',
1227 'title' => 'New Smart Group',
9099cab3
CW
1228 'parents' => [$groupID => 1],
1229 ]
cc949606 1230 );
1231
9099cab3 1232 $actionScheduleParams = [
cc949606 1233 'name' => 'sched_contact_bday_yesterday',
1234 'title' => 'sched_contact_bday_yesterday',
1235 'absolute_date' => '',
1236 'body_html' => '<p>you look like you were born yesterday!</p>',
1237 'body_text' => 'you look like you were born yesterday!',
1238 'end_action' => '',
1239 'end_date' => '',
1240 'end_frequency_interval' => '',
1241 'end_frequency_unit' => '',
1242 'entity_status' => 1,
1243 'entity_value' => 'birth_date',
1244 'limit_to' => 1,
1245 'group_id' => $groupID,
1246 'is_active' => 1,
1247 'is_repeat' => '0',
1248 'mapping_id' => 6,
1249 'msg_template_id' => '',
1250 'recipient' => '2',
1251 'recipient_listing' => '',
1252 'recipient_manual' => '',
1253 'record_activity' => 1,
1254 'repetition_frequency_interval' => '',
1255 'repetition_frequency_unit' => '',
1256 'start_action_condition' => 'after',
1257 'start_action_date' => 'date_field',
1258 'start_action_offset' => '1',
1259 'start_action_unit' => 'day',
1260 'subject' => 'subject sched_contact_bday_yesterday',
9099cab3 1261 ];
cc949606 1262
1263 // Create schedule reminder where parent group ($groupID) is selectd to limit recipients,
1264 // which contain a individual contact - $contactID2 and is parent to smart group.
1265 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionScheduleParams);
1266 $this->assertTrue(is_numeric($actionScheduleDao->id));
9099cab3
CW
1267 $this->assertCronRuns([
1268 [
cc949606 1269 // On the birthday, no email.
1270 'time' => '2005-07-07 01:00:00',
9099cab3
CW
1271 'recipients' => [],
1272 ],
1273 [
cc949606 1274 // The next day, send an email.
1275 'time' => '2005-07-08 20:00:00',
9099cab3
CW
1276 'recipients' => [
1277 [
cc949606 1278 'def@test.com',
9099cab3
CW
1279 ],
1280 [
cc949606 1281 'abc@test.com',
9099cab3
CW
1282 ],
1283 ],
1284 ],
1285 ]);
cc949606 1286 $this->groupDelete($smartGroupID);
1287 $this->groupDelete($groupID);
1288 }
1289
6a488035 1290 /**
442cf836
EM
1291 * Test end date email sent.
1292 *
6a488035
TO
1293 * For contacts/members which match schedule based on join date,
1294 * an email should be sent.
34662dda 1295 *
1296 * @throws \API_Exception
1297 * @throws \Civi\API\Exception\UnauthorizedException
6a488035 1298 */
92c99a4a 1299 public function testMembershipJoinDateNonMatch() {
34662dda 1300 $this->createMembershipFromFixture('rolling_membership', '', ['email' => 'test-member@example.com']);
6a488035 1301 // Add an alternative membership type, and only send messages for that type
9099cab3 1302 $extraMembershipType = $this->createTestObject('CRM_Member_DAO_MembershipType', []);
34662dda 1303 $this->assertInternalType('numeric', $extraMembershipType->id);
cee19268 1304 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($this->fixtures['sched_membership_join_2week']);
34662dda 1305 $this->assertInternalType('numeric', $actionScheduleDao->id);
6a488035
TO
1306 $actionScheduleDao->entity_value = $extraMembershipType->id;
1307 $actionScheduleDao->save();
1308
1309 // start_date=2012-03-15 ; schedule is 2 weeks after start_date
9099cab3
CW
1310 $this->assertCronRuns([
1311 [
567b2076 1312 // After the 2-week mark, don't send email because we have different membership type.
6a488035 1313 'time' => '2012-03-29 01:00:00',
9099cab3
CW
1314 'recipients' => [],
1315 ],
1316 ]);
6a488035
TO
1317 }
1318
861d11c4 1319 /**
442cf836 1320 * Test that the first and SECOND notifications are sent out.
34662dda 1321 *
1322 * @throws \CRM_Core_Exception
861d11c4 1323 */
92c99a4a 1324 public function testMembershipEndDateRepeat() {
861d11c4 1325 // creates membership with end_date = 20120615
34662dda 1326 $membership = $this->createMembershipFromFixture('rolling_membership', 'Current');
1327 $this->callAPISuccess('Email', 'create', [
861d11c4
DG
1328 'contact_id' => $membership->contact_id,
1329 'email' => 'test-member@example.com',
9099cab3
CW
1330 ]);
1331 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
861d11c4
DG
1332
1333 $actionSchedule = $this->fixtures['sched_membership_end_2month_repeat_twice_4_weeks'];
1334 $actionSchedule['entity_value'] = $membership->membership_type_id;
1335 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
1336
1337 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1338 $this->assertCronRuns([
1339 [
e08fae02
PH
1340 // After the 1-month mark, no email
1341 'time' => '2012-07-15 01:00:00',
9099cab3
CW
1342 'recipients' => [],
1343 ],
1344 [
e08fae02 1345 // After the 2-month mark, send an email.
861d11c4 1346 'time' => '2012-08-15 01:00:00',
9099cab3
CW
1347 'recipients' => [['test-member@example.com']],
1348 ],
1349 [
e08fae02 1350 // 4 weeks after first email send first repeat
861d11c4 1351 'time' => '2012-09-12 01:00:00',
9099cab3
CW
1352 'recipients' => [['test-member@example.com']],
1353 ],
1354 [
e08fae02
PH
1355 // 1 week after first repeat send nothing
1356 // There was a bug where the first repeat went out and then
1357 // it would keep going out every cron run. This is to check that's
1358 // not happening.
1359 'time' => '2012-09-19 01:00:00',
9099cab3
CW
1360 'recipients' => [],
1361 ],
1362 [
e08fae02
PH
1363 // 4 weeks after first repeat send second repeat
1364 'time' => '2012-10-10 01:00:00',
9099cab3
CW
1365 'recipients' => [['test-member@example.com']],
1366 ],
1367 [
e08fae02
PH
1368 // 4 months after membership end, send nothing
1369 'time' => '2012-10-15 01:00:00',
9099cab3
CW
1370 'recipients' => [],
1371 ],
1372 [
e08fae02
PH
1373 // 5 months after membership end, send nothing
1374 'time' => '2012-11-15 01:00:00',
9099cab3
CW
1375 'recipients' => [],
1376 ],
1377 ]);
861d11c4
DG
1378 }
1379
1380 /**
442cf836
EM
1381 * Test behaviour when date changes.
1382 *
861d11c4
DG
1383 * Test that the first notification is sent but the second is NOT sent if the end date changes in
1384 * between
1385 * see CRM-15376
34662dda 1386 *
1387 * @throws \CRM_Core_Exception
861d11c4 1388 */
92c99a4a 1389 public function testMembershipEndDateRepeatChangedEndDate_CRM_15376() {
861d11c4 1390 // creates membership with end_date = 20120615
34662dda 1391 $membership = $this->createMembershipFromFixture('rolling_membership', 'Current');
9099cab3 1392 $this->callAPISuccess('Email', 'create', [
861d11c4
DG
1393 'contact_id' => $membership->contact_id,
1394 'email' => 'test-member@example.com',
9099cab3
CW
1395 ]);
1396 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
861d11c4
DG
1397
1398 $actionSchedule = $this->fixtures['sched_membership_end_2month_repeat_twice_4_weeks'];
1399 $actionSchedule['entity_value'] = $membership->membership_type_id;
1400 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
1401 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1402 $this->assertCronRuns([
1403 [
567b2076 1404 // After the 2-week mark, send an email.
861d11c4 1405 'time' => '2012-08-15 01:00:00',
9099cab3
CW
1406 'recipients' => [['test-member@example.com']],
1407 ],
1408 ]);
861d11c4 1409
442cf836 1410 // Extend membership - reminder should NOT go out.
9099cab3
CW
1411 $this->callAPISuccess('membership', 'create', ['id' => $membership->id, 'end_date' => '2014-01-01']);
1412 $this->assertCronRuns([
1413 [
442cf836 1414 // After the 2-week mark, send an email.
861d11c4 1415 'time' => '2012-09-12 01:00:00',
9099cab3
CW
1416 'recipients' => [],
1417 ],
1418 ]);
861d11c4
DG
1419 }
1420
6a488035 1421 /**
442cf836
EM
1422 * Test membership end date email sends.
1423 *
6a488035
TO
1424 * For contacts/members which match schedule based on end date,
1425 * an email should be sent.
34662dda 1426 *
1427 * @throws \CRM_Core_Exception
6a488035 1428 */
92c99a4a 1429 public function testMembershipEndDateMatch() {
6a488035 1430 // creates membership with end_date = 20120615
34662dda 1431 $membership = $this->createMembershipFromFixture('rolling_membership', 'Current');
9099cab3 1432 $this->callAPISuccess('Email', 'create', [
6a488035
TO
1433 'contact_id' => $membership->contact_id,
1434 'email' => 'test-member@example.com',
9099cab3
CW
1435 ]);
1436 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
6a488035
TO
1437
1438 $actionSchedule = $this->fixtures['sched_membership_end_2week'];
1439 $actionSchedule['entity_value'] = $membership->membership_type_id;
cee19268 1440 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
6a488035
TO
1441 $this->assertTrue(is_numeric($actionScheduleDao->id));
1442
1443 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1444 $this->assertCronRuns([
1445 [
442cf836 1446 // Before the 2-week mark, no email.
6a488035 1447 'time' => '2012-05-31 01:00:00',
9099cab3
CW
1448 'recipients' => [],
1449 ],
1450 [
442cf836 1451 // After the 2-week mark, send an email.
6a488035 1452 'time' => '2012-06-01 01:00:00',
9099cab3
CW
1453 'recipients' => [['test-member@example.com']],
1454 ],
1455 [
e08fae02
PH
1456 // After the email is sent, another one is not sent
1457 'time' => '2012-06-01 02:00:00',
9099cab3
CW
1458 'recipients' => [],
1459 ],
1460 ]);
d2868251 1461
1462 // Now suppose user has renewed for rolling membership after 3 months, so upcoming assertion is written
1463 // to ensure that new reminder is sent 2 week before the new end_date i.e. '2012-09-15'
1464 $membership->end_date = '2012-09-15';
1465 $membership->save();
1466
1467 //change the email id of chosen membership contact to assert
1468 //recipient of not the previously sent mail but the new one
9099cab3 1469 $result = $this->callAPISuccess('Email', 'create', [
d2868251 1470 'is_primary' => 1,
1471 'contact_id' => $membership->contact_id,
cbcb7579 1472 'email' => 'member2@example.com',
9099cab3 1473 ]);
d2868251 1474 $this->assertAPISuccess($result);
1475
1476 // end_date=2012-09-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1477 $this->assertCronRuns([
1478 [
cbcb7579 1479 // Before the 2-week mark, no email
d2868251 1480 'time' => '2012-08-31 01:00:00',
9099cab3
CW
1481 'recipients' => [],
1482 ],
1483 [
e08fae02
PH
1484 // After the 2-week mark, send an email
1485 'time' => '2012-09-01 01:00:00',
9099cab3
CW
1486 'recipients' => [['member2@example.com']],
1487 ],
1488 [
e08fae02
PH
1489 // After the email is sent, another one is not sent
1490 'time' => '2012-09-01 02:00:00',
9099cab3
CW
1491 'recipients' => [],
1492 ],
1493 ]);
e08fae02
PH
1494
1495 $membership->end_date = '2012-12-15';
1496 $membership->save();
1497 // end_date=2012-12-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1498 $this->assertCronRuns([
1499 [
e08fae02
PH
1500 // Before the 2-week mark, no email
1501 'time' => '2012-11-30 01:00:00',
9099cab3
CW
1502 'recipients' => [],
1503 ],
1504 [
e08fae02
PH
1505 // After the 2-week mark, send an email
1506 'time' => '2012-12-01 01:00:00',
9099cab3
CW
1507 'recipients' => [['member2@example.com']],
1508 ],
1509 [
e08fae02
PH
1510 // After the email is sent, another one is not sent
1511 'time' => '2012-12-01 02:00:00',
9099cab3
CW
1512 'recipients' => [],
1513 ],
1514 ]);
e08fae02
PH
1515
1516 }
1517
34662dda 1518 /**
1519 * @param array $contactFixture
1520 * @param int $membershipTypeId
1521 *
1522 * @return array|NULL|object
1523 * @throws \CRM_Core_Exception
1524 */
e08fae02
PH
1525 public function createMembershipAndContact($contactFixture, $membershipTypeId) {
1526 $result = $this->callAPISuccess('contact', 'create', $contactFixture);
1527 $contact = $result['values'][$result['id']];
9099cab3 1528 $params = [
e08fae02
PH
1529 'status_id' => 2,
1530 'contact_id' => $contact['id'],
1531 'membership_type_id' => $membershipTypeId,
1532 'owner_membership_id' => 'NULL',
9099cab3 1533 ];
e08fae02
PH
1534 $params = array_merge($this->fixtures['rolling_membership'], $params);
1535 $membership = $this->createTestObject('CRM_Member_DAO_Membership', $params);
34662dda 1536 $this->assertInternalType('numeric', $membership->id);
e08fae02
PH
1537 return $membership;
1538 }
1539
1540 /**
1541 * This test is very similar to testMembershipEndDateMatch, but it adds
1542 * another contact because there was a bug in
1543 * RecipientBuilder::buildRelFirstPass where it was only sending the
1544 * reminder for the first contact returned in a query for renewed
1545 * memberships. Other contacts wouldn't get the mail.
34662dda 1546 *
1547 * @throws \CRM_Core_Exception
e08fae02
PH
1548 */
1549 public function testMultipleMembershipEndDateMatch() {
1550 $membershipTypeId = $this->membershipTypeCreate($this->fixtures['rolling_membership']['membership_type_id']);
1551 $membershipOne = $this->createMembershipAndContact($this->fixtures['contact'], $membershipTypeId);
1552 $membershipTwo = $this->createMembershipAndContact($this->fixtures['contact_2'], $membershipTypeId);
1553 $actionSchedule = $this->fixtures['sched_membership_end_2week'];
1554 $actionSchedule['entity_value'] = $membershipTypeId;
1555 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1556 $this->assertTrue(is_numeric($actionScheduleDao->id));
1557
1558 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1559 $this->assertCronRuns([
1560 [
e08fae02
PH
1561 // Before the 2-week mark, no email.
1562 'time' => '2012-05-31 01:00:00',
9099cab3
CW
1563 'recipients' => [],
1564 ],
1565 [
e08fae02
PH
1566 // After the 2-week mark, send emails.
1567 'time' => '2012-06-01 01:00:00',
9099cab3
CW
1568 'recipients' => [
1569 ['test-member@example.com'],
1570 ['test-contact-2@example.com'],
1571 ],
1572 ],
1573 [
e08fae02
PH
1574 // After the email is sent, another one is not sent
1575 'time' => '2012-06-01 02:00:00',
9099cab3
CW
1576 'recipients' => [],
1577 ],
1578 ]);
e08fae02
PH
1579
1580 // Now suppose user has renewed for rolling membership after 3 months, so upcoming assertion is written
1581 // to ensure that new reminder is sent 2 week before the new end_date i.e. '2012-09-15'
1582 $membershipOne->end_date = '2012-09-15';
1583 $membershipOne->save();
1584 $membershipTwo->end_date = '2012-09-15';
1585 $membershipTwo->save();
1586
1587 // end_date=2012-09-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1588 $this->assertCronRuns([
1589 [
e08fae02
PH
1590 // Before the 2-week mark, no email
1591 'time' => '2012-08-31 01:00:00',
9099cab3
CW
1592 'recipients' => [],
1593 ],
1594 [
e08fae02
PH
1595 // After the 2-week mark, send an email
1596 'time' => '2012-09-01 01:00:00',
9099cab3
CW
1597 'recipients' => [
1598 ['test-member@example.com'],
1599 ['test-contact-2@example.com'],
1600 ],
1601 ],
1602 [
e08fae02
PH
1603 // After the email is sent, another one is not sent
1604 'time' => '2012-06-01 02:00:00',
9099cab3
CW
1605 'recipients' => [],
1606 ],
1607 ]);
6a488035
TO
1608 }
1609
4b1efa1d 1610 /**
442cf836
EM
1611 * Test membership end date email.
1612 *
6c6e6187
TO
1613 * For contacts/members which match schedule based on end date,
1614 * an email should be sent.
34662dda 1615 *
1616 * @throws \CRM_Core_Exception
6c6e6187 1617 */
92c99a4a 1618 public function testMembershipEndDateNoMatch() {
4b1efa1d 1619 // creates membership with end_date = 20120615
34662dda 1620 $membership = $this->createMembershipFromFixture('rolling_membership', 'Grace');
1621 $this->callAPISuccess('Email', 'create', [
4b1efa1d 1622 'contact_id' => $membership->contact_id,
1623 'email' => 'test-member@example.com',
9099cab3
CW
1624 ]);
1625 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
4b1efa1d 1626
1627 $actionSchedule = $this->fixtures['sched_membership_end_2month'];
1628 $actionSchedule['entity_value'] = $membership->membership_type_id;
cee19268 1629 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
4b1efa1d 1630 $this->assertTrue(is_numeric($actionScheduleDao->id));
1631
1632 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1633 $this->assertCronRuns([
1634 [
442cf836 1635 // Before the 2-week mark, no email.
4b1efa1d 1636 'time' => '2012-05-31 01:00:00',
9099cab3
CW
1637 'recipients' => [],
1638 ],
1639 [
e08fae02 1640 // After the 2-week mark, no email
4b1efa1d 1641 'time' => '2013-05-01 01:00:00',
9099cab3
CW
1642 'recipients' => [],
1643 ],
1644 ]);
4b1efa1d 1645 }
1646
34662dda 1647 /**
1648 * @throws \CRM_Core_Exception
1649 */
92c99a4a 1650 public function testContactBirthDateNoAnniv() {
bf308d29 1651 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
43030baf
AH
1652 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1653 $actionSchedule = $this->fixtures['sched_contact_bday_yesterday'];
1654 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 1655 $this->assertInternalType('numeric', $actionScheduleDao->id);
9099cab3
CW
1656 $this->assertCronRuns([
1657 [
442cf836 1658 // On the birthday, no email.
43030baf 1659 'time' => '2005-07-07 01:00:00',
9099cab3
CW
1660 'recipients' => [],
1661 ],
1662 [
442cf836 1663 // The next day, send an email.
43030baf 1664 'time' => '2005-07-08 20:00:00',
9099cab3
CW
1665 'recipients' => [['test-bday@example.com']],
1666 ],
1667 ]);
43030baf
AH
1668 }
1669
34662dda 1670 /**
1671 * @throws \CRM_Core_Exception
1672 */
92c99a4a 1673 public function testContactBirthDateAnniversary() {
6c6e6187 1674 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
43030baf
AH
1675 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1676 $actionSchedule = $this->fixtures['sched_contact_bday_anniv'];
1677 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1678 $this->assertTrue(is_numeric($actionScheduleDao->id));
9099cab3
CW
1679 $this->assertCronRuns([
1680 [
92c99a4a 1681 // On some random day, no email.
43030baf 1682 'time' => '2014-03-07 01:00:00',
9099cab3
CW
1683 'recipients' => [],
1684 ],
1685 [
92c99a4a 1686 // On the eve of their 9th birthday, send an email.
43030baf 1687 'time' => '2014-07-06 20:00:00',
9099cab3
CW
1688 'recipients' => [['test-bday@example.com']],
1689 ],
1690 ]);
43030baf 1691 }
4b1efa1d 1692
34662dda 1693 /**
1694 * @throws \CRM_Core_Exception
1695 */
1696 public function testContactCustomDateNoAnniversary() {
9099cab3 1697 $group = [
43030baf
AH
1698 'title' => 'Test_Group',
1699 'name' => 'test_group',
9099cab3 1700 'extends' => ['Individual'],
43030baf 1701 'style' => 'Inline',
6c6e6187 1702 'is_multiple' => FALSE,
43030baf 1703 'is_active' => 1,
9099cab3 1704 ];
bf308d29 1705 $createGroup = $this->callAPISuccess('custom_group', 'create', $group);
9099cab3 1706 $field = [
43030baf
AH
1707 'label' => 'Graduation',
1708 'data_type' => 'Date',
1709 'html_type' => 'Select Date',
1710 'custom_group_id' => $createGroup['id'],
9099cab3 1711 ];
bf308d29 1712 $createField = $this->callAPISuccess('custom_field', 'create', $field);
43030baf
AH
1713 $contactParams = $this->fixtures['contact'];
1714 $contactParams["custom_{$createField['id']}"] = '2013-12-16';
bf308d29 1715 $contact = $this->callAPISuccess('Contact', 'create', $contactParams);
43030baf
AH
1716 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
1717 $actionSchedule = $this->fixtures['sched_contact_grad_tomorrow'];
1718 $actionSchedule['entity_value'] = "custom_{$createField['id']}";
1719 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1720 $this->assertTrue(is_numeric($actionScheduleDao->id));
9099cab3
CW
1721 $this->assertCronRuns([
1722 [
92c99a4a 1723 // On some random day, no email.
43030baf 1724 'time' => '2014-03-07 01:00:00',
9099cab3
CW
1725 'recipients' => [],
1726 ],
1727 [
92c99a4a 1728 // On the eve of their graduation, send an email.
43030baf 1729 'time' => '2013-12-15 20:00:00',
9099cab3
CW
1730 'recipients' => [['test-member@example.com']],
1731 ],
1732 ]);
1733 $this->callAPISuccess('custom_group', 'delete', ['id' => $createGroup['id']]);
43030baf 1734 }
92915c55 1735
34662dda 1736 /**
1737 * @throws \CRM_Core_Exception
1738 */
1739 public function testContactCreatedNoAnniversary() {
4aff0253
AH
1740 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
1741 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
34662dda 1742 $this->createScheduleFromFixtures('sched_contact_created_yesterday');
9099cab3
CW
1743 $this->assertCronRuns([
1744 [
4aff0253
AH
1745 // On the date created, no email.
1746 'time' => $contact['values'][$contact['id']]['created_date'],
9099cab3
CW
1747 'recipients' => [],
1748 ],
1749 [
4aff0253
AH
1750 // The next day, send an email.
1751 'time' => date('Y-m-d H:i:s', strtotime($contact['values'][$contact['id']]['created_date'] . ' +1 day')),
9099cab3
CW
1752 'recipients' => [['test-bday@example.com']],
1753 ],
1754 ]);
4aff0253
AH
1755 }
1756
34662dda 1757 /**
1758 * Test the impact of changing the anniversary.
1759 *
1760 * @throws \CRM_Core_Exception
1761 */
4aff0253
AH
1762 public function testContactModifiedAnniversary() {
1763 $contact = $this->callAPISuccess('Contact', 'create', $this->fixtures['contact_birthdate']);
1764 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
9099cab3 1765 $modifiedDate = $this->callAPISuccess('Contact', 'getvalue', ['id' => $contact['id'], 'return' => 'modified_date']);
4aff0253
AH
1766 $actionSchedule = $this->fixtures['sched_contact_mod_anniv'];
1767 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 1768 $this->assertInternalType('numeric', $actionScheduleDao->id);
9099cab3
CW
1769 $this->assertCronRuns([
1770 [
4aff0253 1771 // On some random day, no email.
a9ac9f6c 1772 'time' => date('Y-m-d H:i:s', strtotime($contact['values'][$contact['id']]['modified_date'] . ' -60 days')),
9099cab3
CW
1773 'recipients' => [],
1774 ],
1775 [
4aff0253 1776 // On the eve of 3 years after they were modified, send an email.
688bd604 1777 'time' => date('Y-m-d H:i:s', strtotime($modifiedDate . ' +3 years -1 day')),
9099cab3
CW
1778 'recipients' => [['test-bday@example.com']],
1779 ],
1780 ]);
4aff0253
AH
1781 }
1782
baa85770 1783 /**
92c99a4a 1784 * Check that limit_to + an empty recipients doesn't sent to multiple contacts.
34662dda 1785 *
1786 * @throws \API_Exception
1787 * @throws \CRM_Core_Exception
1788 * @throws \Civi\API\Exception\UnauthorizedException
baa85770 1789 */
00be9182 1790 public function testMembershipLimitToNone() {
baa85770 1791 // creates membership with end_date = 20120615
34662dda 1792 $membership = $this->createMembershipFromFixture('rolling_membership', 'Current');
9099cab3 1793 $result = $this->callAPISuccess('Email', 'create', [
baa85770
EM
1794 'contact_id' => $membership->contact_id,
1795 'email' => 'member@example.com',
9099cab3
CW
1796 ]);
1797 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
1798 $this->callAPISuccess('contact', 'create', ['email' => 'b@c.com', 'contact_type' => 'Individual']);
baa85770
EM
1799
1800 $this->assertAPISuccess($result);
1801
1802 $actionSchedule = $this->fixtures['sched_membership_end_limit_to_none'];
1803 $actionSchedule['entity_value'] = $membership->membership_type_id;
1804 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
1805 $this->assertTrue(is_numeric($actionScheduleDao->id));
1806
1807 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
1808 $this->assertCronRuns([
1809 [
92c99a4a 1810 // Before the 2-week mark, no email.
baa85770
EM
1811 'time' => '2012-05-31 01:00:00',
1812 // 'time' => '2012-06-01 01:00:00', // FIXME: Is this the right boundary?
9099cab3
CW
1813 'recipients' => [],
1814 ],
1815 ]);
baa85770
EM
1816 }
1817
34662dda 1818 /**
1819 * Test handling of reference date for memberships.
1820 *
1821 * @throws \API_Exception
1822 * @throws \CRM_Core_Exception
1823 * @throws \Civi\API\Exception\UnauthorizedException
1824 */
1825 public function testMembershipWithReferenceDate() {
1826 $membership = $this->createMembershipFromFixture('rolling_membership', 'Current', ['email' => 'member@example.com']);
1827 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
5c4d6559 1828
1829 $actionSchedule = $this->fixtures['sched_membership_join_2week'];
1830 $actionSchedule['entity_value'] = $membership->membership_type_id;
1831 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 1832 $this->assertInternalType('numeric', $actionScheduleDao->id);
5c4d6559 1833
1834 // start_date=2012-03-15 ; schedule is 2 weeks after start_date
9099cab3
CW
1835 $this->assertCronRuns([
1836 [
cbcb7579 1837 // After the 2-week mark, send an email
5c4d6559 1838 'time' => '2012-03-29 01:00:00',
9099cab3
CW
1839 'recipients' => [['member@example.com']],
1840 ],
1841 [
cbcb7579 1842 // After the 2-week 1day mark, don't send an email
9c0fe051 1843 'time' => '2012-03-30 01:00:00',
9099cab3
CW
1844 'recipients' => [],
1845 ],
1846 ]);
5c4d6559 1847
1848 //check if reference date is set to membership's join date
1849 //as per the action_start_date chosen for current schedule reminder
e08fae02 1850 $this->assertEquals('2012-03-15 00:00:00',
5c4d6559 1851 CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $membership->contact_id, 'reference_date', 'contact_id')
1852 );
1853
e7c6a902 1854 //change current membership join date that may signifies as membership renewal activity
5c4d6559 1855 $membership->join_date = '2012-03-29';
1856 $membership->save();
1857
9099cab3
CW
1858 $this->assertCronRuns([
1859 [
cbcb7579 1860 // After the 13 days of the changed join date 2012-03-29, don't send an email
9c0fe051 1861 'time' => '2012-04-11 01:00:00',
9099cab3
CW
1862 'recipients' => [],
1863 ],
1864 [
cbcb7579 1865 // After the 2-week of the changed join date 2012-03-29, send an email
5c4d6559 1866 'time' => '2012-04-12 01:00:00',
9099cab3
CW
1867 'recipients' => [['member@example.com']],
1868 ],
1869 ]);
1870 $this->assertCronRuns([
1871 [
7d48c97b 1872 // It should not re-send on the same day
1873 'time' => '2012-04-12 01:00:00',
9099cab3
CW
1874 'recipients' => [],
1875 ],
1876 ]);
5c4d6559 1877 }
baa85770 1878
34662dda 1879 /**
1880 * Test multiple membership reminder.
1881 *
1882 * @throws \API_Exception
1883 * @throws \CRM_Core_Exception
1884 * @throws \Civi\API\Exception\UnauthorizedException
1885 */
d2868251 1886 public function testMembershipOnMultipleReminder() {
34662dda 1887 $membership = $this->createMembershipFromFixture('rolling_membership', 'Current', ['email' => 'member@example.com']);
1888 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
d2868251 1889
39b959db
SL
1890 // Send email 2 weeks before end_date
1891 $actionScheduleBefore = $this->fixtures['sched_membership_end_2week'];
1892 // Send email on end_date/expiry date
1893 $actionScheduleOn = $this->fixtures['sched_on_membership_end_date'];
1894 // Send email 1 day after end_date/grace period
1895 $actionScheduleAfter = $this->fixtures['sched_after_1day_membership_end_date'];
d2868251 1896 $actionScheduleBefore['entity_value'] = $actionScheduleOn['entity_value'] = $actionScheduleAfter['entity_value'] = $membership->membership_type_id;
9099cab3 1897 foreach (['actionScheduleBefore', 'actionScheduleOn', 'actionScheduleAfter'] as $value) {
d2868251 1898 $$value = CRM_Core_BAO_ActionSchedule::add($$value);
34662dda 1899 $this->assertInternalType('numeric', $$value->id);
d2868251 1900 }
1901
1902 $this->assertCronRuns(
9099cab3
CW
1903 [
1904 [
cbcb7579 1905 // 1day 2weeks before membership end date(MED), don't send mail
d2868251 1906 'time' => '2012-05-31 01:00:00',
9099cab3
CW
1907 'recipients' => [],
1908 ],
1909 [
cbcb7579 1910 // 2 weeks before MED, send an email
d2868251 1911 'time' => '2012-06-01 01:00:00',
9099cab3
CW
1912 'recipients' => [['member@example.com']],
1913 ],
1914 [
cbcb7579 1915 // 1day before MED, don't send mail
d2868251 1916 'time' => '2012-06-14 01:00:00',
9099cab3
CW
1917 'recipients' => [],
1918 ],
1919 [
cbcb7579 1920 // On MED, send an email
d2868251 1921 'time' => '2012-06-15 00:00:00',
9099cab3
CW
1922 'recipients' => [['member@example.com']],
1923 ],
1924 [
cbcb7579 1925 // After 1day of MED, send an email
d2868251 1926 'time' => '2012-06-16 01:00:00',
9099cab3
CW
1927 'recipients' => [['member@example.com']],
1928 ],
1929 [
cbcb7579 1930 // After 1day 1min of MED, don't send an email
d2868251 1931 'time' => '2012-06-17 00:01:00',
9099cab3
CW
1932 'recipients' => [],
1933 ],
1934 ]
cbcb7579 1935 );
d2868251 1936
1937 // Assert the timestamp as of when the emails of respective three reminders as configured
1938 // 2 weeks before, on and 1 day after MED, are sent
f42ab010
TO
1939 $this->assertApproxEquals(
1940 strtotime('2012-06-01 01:00:00'),
1941 strtotime(CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $actionScheduleBefore->id, 'action_date_time', 'action_schedule_id', TRUE)),
39b959db
SL
1942 // Variation in test execution time.
1943 3
f42ab010
TO
1944 );
1945 $this->assertApproxEquals(
1946 strtotime('2012-06-15 00:00:00'),
1947 strtotime(CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $actionScheduleOn->id, 'action_date_time', 'action_schedule_id', TRUE)),
39b959db
SL
1948 // Variation in test execution time.
1949 3
f42ab010
TO
1950 );
1951 $this->assertApproxEquals(
1952 strtotime('2012-06-16 01:00:00'),
1953 strtotime(CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionLog', $actionScheduleAfter->id, 'action_date_time', 'action_schedule_id', TRUE)),
39b959db
SL
1954 // Variation in test execution time.
1955 3
f42ab010 1956 );
d2868251 1957
e7c6a902 1958 //extend MED to 2 weeks after the current MED (that may signifies as membership renewal activity)
d2868251 1959 // and lets assert as of when the new set of reminders will be sent against their respective Schedule Reminders(SR)
9c0fe051 1960 $membership->end_date = '2012-06-20';
d2868251 1961 $membership->save();
d2868251 1962
34662dda 1963 $this->callAPISuccess('Contact', 'get', ['id' => $membership->contact_id]);
d2868251 1964 $this->assertCronRuns(
9099cab3
CW
1965 [
1966 [
cbcb7579 1967 // 1day 2weeks before membership end date(MED), don't send mail
9c0fe051 1968 'time' => '2012-06-05 01:00:00',
9099cab3
CW
1969 'recipients' => [],
1970 ],
1971 [
cbcb7579 1972 // 2 weeks before MED, send an email
9c0fe051 1973 'time' => '2012-06-06 01:00:00',
9099cab3
CW
1974 'recipients' => [['member@example.com']],
1975 ],
1976 [
cbcb7579 1977 // 1day before MED, don't send mail
9c0fe051 1978 'time' => '2012-06-19 01:00:00',
9099cab3
CW
1979 'recipients' => [],
1980 ],
1981 [
cbcb7579 1982 // On MED, send an email
9c0fe051 1983 'time' => '2012-06-20 00:00:00',
9099cab3
CW
1984 'recipients' => [['member@example.com']],
1985 ],
1986 [
cbcb7579 1987 // After 1day of MED, send an email
9c0fe051 1988 'time' => '2012-06-21 01:00:00',
9099cab3
CW
1989 'recipients' => [['member@example.com']],
1990 ],
1991 [
cbcb7579 1992 // After 1day 1min of MED, don't send an email
9c0fe051 1993 'time' => '2012-07-21 00:01:00',
9099cab3
CW
1994 'recipients' => [],
1995 ],
1996 ]);
d2868251 1997 }
1998
34662dda 1999 /**
2000 * Test reminders sent on custom data anniversary.
2001 *
2002 * @throws \CRM_Core_Exception
2003 */
2004 public function testContactCustomDate_Anniversary() {
9099cab3 2005 $group = [
43030baf
AH
2006 'title' => 'Test_Group now',
2007 'name' => 'test_group_now',
9099cab3 2008 'extends' => ['Individual'],
43030baf 2009 'style' => 'Inline',
6c6e6187 2010 'is_multiple' => FALSE,
43030baf 2011 'is_active' => 1,
9099cab3 2012 ];
bf308d29 2013 $createGroup = $this->callAPISuccess('custom_group', 'create', $group);
9099cab3 2014 $field = [
43030baf
AH
2015 'label' => 'Graduation',
2016 'data_type' => 'Date',
2017 'html_type' => 'Select Date',
2018 'custom_group_id' => $createGroup['id'],
9099cab3 2019 ];
bf308d29
EM
2020 $createField = $this->callAPISuccess('custom_field', 'create', $field);
2021
43030baf
AH
2022 $contactParams = $this->fixtures['contact'];
2023 $contactParams["custom_{$createField['id']}"] = '2013-12-16';
bf308d29 2024 $contact = $this->callAPISuccess('Contact', 'create', $contactParams);
43030baf
AH
2025 $this->_testObjects['CRM_Contact_DAO_Contact'][] = $contact['id'];
2026 $actionSchedule = $this->fixtures['sched_contact_grad_anniv'];
2027 $actionSchedule['entity_value'] = "custom_{$createField['id']}";
2028 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
2029 $this->assertTrue(is_numeric($actionScheduleDao->id));
9099cab3
CW
2030 $this->assertCronRuns([
2031 [
92c99a4a 2032 // On some random day, no email.
43030baf 2033 'time' => '2014-03-07 01:00:00',
9099cab3
CW
2034 'recipients' => [],
2035 ],
2036 [
92c99a4a 2037 // A week after their 5th anniversary of graduation, send an email.
43030baf 2038 'time' => '2018-12-23 20:00:00',
9099cab3
CW
2039 'recipients' => [['test-member@example.com']],
2040 ],
2041 ]);
2042 $this->callAPISuccess('custom_group', 'delete', ['id' => $createGroup['id']]);
43030baf 2043 }
4b1efa1d 2044
76ea51c7
JP
2045 /**
2046 * Test sched reminder set via registration date.
34662dda 2047 *
2048 * @throws \CRM_Core_Exception
76ea51c7
JP
2049 */
2050 public function testEventTypeRegistrationDate() {
34662dda 2051 $contact = $this->individualCreate(['email' => 'test-event@example.com']);
76ea51c7 2052 //Add it as a participant to an event ending registration - 7 days from now.
9099cab3 2053 $params = [
76ea51c7
JP
2054 'start_date' => date('Ymd', strtotime('-5 day')),
2055 'end_date' => date('Ymd', strtotime('+7 day')),
2056 'registration_start_date' => date('Ymd', strtotime('-5 day')),
2057 'registration_end_date' => date('Ymd', strtotime('+7 day')),
9099cab3 2058 ];
76ea51c7 2059 $event = $this->eventCreate($params);
9099cab3 2060 $this->participantCreate(['contact_id' => $contact, 'event_id' => $event['id']]);
76ea51c7
JP
2061
2062 //Create a scheduled reminder to send email 7 days before registration date.
2063 $actionSchedule = $this->fixtures['sched_eventtype_start_1week_before'];
2064 $actionSchedule['start_action_offset'] = 7;
2065 $actionSchedule['start_action_unit'] = 'day';
2066 $actionSchedule['start_action_date'] = 'registration_end_date';
2067 $actionSchedule['entity_value'] = $event['values'][$event['id']]['event_type_id'];
9099cab3 2068 $actionSchedule['entity_status'] = $this->callAPISuccessGetValue('ParticipantStatusType', [
34662dda 2069 'return' => 'id',
2070 'name' => 'Attended',
9099cab3 2071 ]);
899bd155 2072 $actionSched = $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
76ea51c7 2073 //Run the cron and verify if an email was sent.
9099cab3
CW
2074 $this->assertCronRuns([
2075 [
76ea51c7 2076 'time' => date('Y-m-d'),
9099cab3
CW
2077 'recipients' => [['test-event@example.com']],
2078 ],
2079 ]);
899bd155
JP
2080
2081 //Create contact 2
9099cab3 2082 $contactParams = [
899bd155 2083 'email' => 'test-event2@example.com',
9099cab3 2084 ];
899bd155
JP
2085 $contact2 = $this->individualCreate($contactParams);
2086 //Create an event with registration end date = 2 week from now.
2087 $params['end_date'] = date('Ymd', strtotime('+2 week'));
2088 $params['registration_end_date'] = date('Ymd', strtotime('+2 week'));
2089 $event2 = $this->eventCreate($params);
9099cab3 2090 $this->participantCreate(['contact_id' => $contact2, 'event_id' => $event2['id']]);
899bd155
JP
2091
2092 //Assert there is no reminder sent to the contact.
9099cab3
CW
2093 $this->assertCronRuns([
2094 [
899bd155 2095 'time' => date('Y-m-d'),
9099cab3
CW
2096 'recipients' => [],
2097 ],
2098 ]);
899bd155
JP
2099
2100 //Modify the sched reminder to be sent 2 week from registration end date.
9099cab3 2101 $this->callAPISuccess('action_schedule', 'create', [
899bd155
JP
2102 'id' => $actionSched['id'],
2103 'start_action_offset' => 2,
2104 'start_action_unit' => 'week',
9099cab3 2105 ]);
899bd155
JP
2106
2107 //Contact should receive the reminder now.
9099cab3
CW
2108 $this->assertCronRuns([
2109 [
899bd155 2110 'time' => date('Y-m-d'),
9099cab3
CW
2111 'recipients' => [['test-event2@example.com']],
2112 ],
2113 ]);
76ea51c7
JP
2114 }
2115
2116 /**
2117 * Test sched reminder set via start date.
34662dda 2118 *
2119 * @throws \CRM_Core_Exception
76ea51c7 2120 */
d3eae6ea
TO
2121 public function testEventTypeStartDate() {
2122 // Create event+participant with start_date = 20120315, end_date = 20120615.
9099cab3
CW
2123 $participant = $this->createTestObject('CRM_Event_DAO_Participant', array_merge($this->fixtures['participant'], ['status_id' => 2]));
2124 $this->callAPISuccess('Email', 'create', [
d3eae6ea
TO
2125 'contact_id' => $participant->contact_id,
2126 'email' => 'test-event@example.com',
9099cab3
CW
2127 ]);
2128 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $participant->contact_id]));
d3eae6ea
TO
2129
2130 $actionSchedule = $this->fixtures['sched_eventtype_start_1week_before'];
2131 $actionSchedule['entity_value'] = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $participant->event_id, 'event_type_id');
2132 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
2133
2134 //echo "CREATED\n"; ob_flush(); sleep(20);
2135
2136 // end_date=2012-06-15 ; schedule is 2 weeks before end_date
9099cab3
CW
2137 $this->assertCronRuns([
2138 [
d3eae6ea
TO
2139 // 2 weeks before
2140 'time' => '2012-03-02 01:00:00',
9099cab3
CW
2141 'recipients' => [],
2142 ],
2143 [
d3eae6ea
TO
2144 // 1 week before
2145 'time' => '2012-03-08 01:00:00',
9099cab3
CW
2146 'recipients' => [['test-event@example.com']],
2147 ],
2148 [
d3eae6ea
TO
2149 // And then nothing else
2150 'time' => '2012-03-16 01:00:00',
9099cab3
CW
2151 'recipients' => [],
2152 ],
2153 ]);
d3eae6ea
TO
2154 }
2155
34662dda 2156 /**
2157 * Test schedule on event end date.
2158 *
2159 * @throws \CRM_Core_Exception
2160 */
d3eae6ea
TO
2161 public function testEventTypeEndDateRepeat() {
2162 // Create event+participant with start_date = 20120315, end_date = 20120615.
9099cab3
CW
2163 $participant = $this->createTestObject('CRM_Event_DAO_Participant', array_merge($this->fixtures['participant'], ['status_id' => 2]));
2164 $this->callAPISuccess('Email', 'create', [
d3eae6ea
TO
2165 'contact_id' => $participant->contact_id,
2166 'email' => 'test-event@example.com',
9099cab3 2167 ]);
34662dda 2168 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $participant->contact_id]));
d3eae6ea
TO
2169
2170 $actionSchedule = $this->fixtures['sched_eventtype_end_2month_repeat_twice_2_weeks'];
2171 $actionSchedule['entity_value'] = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $participant->event_id, 'event_type_id');
2172 $this->callAPISuccess('action_schedule', 'create', $actionSchedule);
2173
9099cab3
CW
2174 $this->assertCronRuns([
2175 [
d3eae6ea
TO
2176 // Almost 2 months.
2177 'time' => '2012-08-13 01:00:00',
9099cab3
CW
2178 'recipients' => [],
2179 ],
2180 [
d3eae6ea
TO
2181 // After the 2-month mark, send an email.
2182 'time' => '2012-08-16 01:00:00',
9099cab3
CW
2183 'recipients' => [['test-event@example.com']],
2184 ],
2185 [
d3eae6ea
TO
2186 // After 2 months and 1 week, don't repeat yet.
2187 'time' => '2012-08-23 02:00:00',
9099cab3
CW
2188 'recipients' => [],
2189 ],
2190 [
d3eae6ea
TO
2191 // After 2 months and 2 weeks
2192 'time' => '2012-08-30 02:00:00',
9099cab3
CW
2193 'recipients' => [['test-event@example.com']],
2194 ],
2195 [
d3eae6ea
TO
2196 // After 2 months and 4 week
2197 'time' => '2012-09-13 02:00:00',
9099cab3
CW
2198 'recipients' => [['test-event@example.com']],
2199 ],
2200 [
d3eae6ea
TO
2201 // After 2 months and 6 weeks
2202 'time' => '2012-09-27 01:00:00',
9099cab3
CW
2203 'recipients' => [],
2204 ],
2205 ]);
d3eae6ea
TO
2206 }
2207
6a488035
TO
2208 // TODO // function testMembershipEndDate_NonMatch() { }
2209 // TODO // function testEventTypeStartDate_Match() { }
2210 // TODO // function testEventTypeEndDate_Match() { }
2211 // TODO // function testEventNameStartDate_Match() { }
2212 // TODO // function testEventNameEndDate_Match() { }
2213
2214 /**
92c99a4a 2215 * Run a series of cron jobs and make an assertion about email deliveries.
6a488035 2216 *
16b10e64
CW
2217 * @param array $cronRuns
2218 * array specifying when to run cron and what messages to expect; each item is an array with keys:
2219 * - time: string, e.g. '2012-06-15 21:00:01'
2220 * - recipients: array(array(string)), list of email addresses which should receive messages
34662dda 2221 *
2222 * @throws \CRM_Core_Exception
6a488035 2223 */
00be9182 2224 public function assertCronRuns($cronRuns) {
6a488035
TO
2225 foreach ($cronRuns as $cronRun) {
2226 CRM_Utils_Time::setTime($cronRun['time']);
9099cab3 2227 $this->callAPISuccess('job', 'send_reminder', []);
6a488035 2228 $this->mut->assertRecipients($cronRun['recipients']);
f8c3594b
TO
2229 if (array_key_exists('subjects', $cronRun)) {
2230 $this->mut->assertSubjects($cronRun['subjects']);
2231 }
6a488035
TO
2232 $this->mut->clearMessages();
2233 }
2234 }
2235
6a488035 2236 /**
1d3260ea
SL
2237 * @var array
2238 * (DAO_Name => array(int)) List of items to garbage-collect during tearDown
6a488035
TO
2239 */
2240 private $_testObjects;
2241
2242 /**
2243 * Sets up the fixture, for example, opens a network connection.
92c99a4a 2244 *
6a488035 2245 * This method is called before a test is executed.
6a488035
TO
2246 */
2247 protected function _setUp() {
9099cab3 2248 $this->_testObjects = [];
6a488035
TO
2249 }
2250
2251 /**
2252 * Tears down the fixture, for example, closes a network connection.
92c99a4a 2253 *
6a488035 2254 * This method is called after a test is executed.
6a488035
TO
2255 */
2256 protected function _tearDown() {
2257 parent::tearDown();
2258 $this->deleteTestObjects();
2259 }
2260
2261 /**
2262 * This is a wrapper for CRM_Core_DAO::createTestObject which tracks
92c99a4a 2263 * created entities and provides for brainless cleanup.
6a488035
TO
2264 *
2265 * @see CRM_Core_DAO::createTestObject
92c99a4a 2266 *
1e1fdcf6
EM
2267 * @param $daoName
2268 * @param array $params
2269 * @param int $numObjects
2270 * @param bool $createOnly
92c99a4a
EM
2271 *
2272 * @return array|NULL|object
6a488035 2273 */
9099cab3 2274 public function createTestObject($daoName, $params = [], $numObjects = 1, $createOnly = FALSE) {
6a488035
TO
2275 $objects = CRM_Core_DAO::createTestObject($daoName, $params, $numObjects, $createOnly);
2276 if (is_array($objects)) {
2277 $this->registerTestObjects($objects);
0db6c3e1
TO
2278 }
2279 else {
9099cab3 2280 $this->registerTestObjects([$objects]);
6a488035
TO
2281 }
2282 return $objects;
2283 }
2284
2285 /**
5a4f6742
CW
2286 * @param array $objects
2287 * DAO or BAO objects.
6a488035 2288 */
00be9182 2289 public function registerTestObjects($objects) {
6a488035
TO
2290 //if (is_object($objects)) {
2291 // $objects = array($objects);
2292 //}
2293 foreach ($objects as $object) {
2294 $daoName = preg_replace('/_BAO_/', '_DAO_', get_class($object));
2295 $this->_testObjects[$daoName][] = $object->id;
2296 }
2297 }
2298
00be9182 2299 public function deleteTestObjects() {
6a488035
TO
2300 // Note: You might argue that the FK relations between test
2301 // objects could make this problematic; however, it should
2302 // behave intuitively as long as we mentally split our
2303 // test-objects between the "manual/primary records"
2304 // and the "automatic/secondary records"
2305 foreach ($this->_testObjects as $daoName => $daoIds) {
2306 foreach ($daoIds as $daoId) {
9099cab3 2307 CRM_Core_DAO::deleteTestObjects($daoName, ['id' => $daoId]);
6a488035
TO
2308 }
2309 }
9099cab3 2310 $this->_testObjects = [];
6a488035
TO
2311 }
2312
52f09320
PH
2313 /**
2314 * Test that the various repetition units work correctly.
2315 * CRM-17028
2316 */
2317 public function testRepetitionFrequencyUnit() {
9099cab3 2318 $membershipTypeParams = [
52f09320
PH
2319 'duration_interval' => '1',
2320 'duration_unit' => 'year',
2321 'is_active' => 1,
2322 'period_type' => 'rolling',
9099cab3 2323 ];
52f09320 2324 $membershipType = $this->createTestObject('CRM_Member_DAO_MembershipType', $membershipTypeParams);
9099cab3 2325 $interval_units = ['hour', 'day', 'week', 'month', 'year'];
52f09320
PH
2326 foreach ($interval_units as $interval_unit) {
2327 $membershipEndDate = DateTime::createFromFormat('Y-m-d H:i:s', "2013-03-15 00:00:00");
9099cab3 2328 $contactParams = [
52f09320
PH
2329 'contact_type' => 'Individual',
2330 'first_name' => 'Test',
2331 'last_name' => "Interval $interval_unit",
2332 'is_deceased' => 0,
9099cab3 2333 ];
52f09320
PH
2334 $contact = $this->createTestObject('CRM_Contact_DAO_Contact', $contactParams);
2335 $this->assertTrue(is_numeric($contact->id));
9099cab3 2336 $emailParams = [
52f09320 2337 'contact_id' => $contact->id,
62ca07e7 2338 'is_primary' => 1,
52f09320
PH
2339 'email' => "test-member-{$interval_unit}@example.com",
2340 'location_type_id' => 1,
9099cab3 2341 ];
52f09320
PH
2342 $email = $this->createTestObject('CRM_Core_DAO_Email', $emailParams);
2343 $this->assertTrue(is_numeric($email->id));
9099cab3 2344 $membershipParams = [
52f09320
PH
2345 'membership_type_id' => $membershipType->id,
2346 'contact_id' => $contact->id,
2347 'join_date' => '20120315',
2348 'start_date' => '20120315',
2349 'end_date' => '20130315',
2350 'is_override' => 0,
2351 'status_id' => 2,
9099cab3 2352 ];
52f09320
PH
2353 $membershipParams['status-id'] = 1;
2354 $membership = $this->createTestObject('CRM_Member_DAO_Membership', $membershipParams);
2355 $actionScheduleParams = $this->fixtures['sched_on_membership_end_date_repeat_interval'];
2356 $actionScheduleParams['entity_value'] = $membershipType->id;
2357 $actionScheduleParams['repetition_frequency_unit'] = $interval_unit;
2358 $actionScheduleParams['repetition_frequency_interval'] = 2;
2359 $actionSchedule = CRM_Core_BAO_ActionSchedule::add($actionScheduleParams);
2360 $this->assertTrue(is_numeric($actionSchedule->id));
2361 $beforeEndDate = $this->createModifiedDateTime($membershipEndDate, '-1 day');
2362 $beforeFirstUnit = $this->createModifiedDateTime($membershipEndDate, "+1 $interval_unit");
2363 $afterFirstUnit = $this->createModifiedDateTime($membershipEndDate, "+2 $interval_unit");
9099cab3
CW
2364 $cronRuns = [
2365 [
52f09320 2366 'time' => $beforeEndDate->format('Y-m-d H:i:s'),
9099cab3
CW
2367 'recipients' => [],
2368 ],
2369 [
52f09320 2370 'time' => $membershipEndDate->format('Y-m-d H:i:s'),
9099cab3
CW
2371 'recipients' => [["test-member-{$interval_unit}@example.com"]],
2372 ],
2373 [
52f09320 2374 'time' => $beforeFirstUnit->format('Y-m-d H:i:s'),
9099cab3
CW
2375 'recipients' => [],
2376 ],
2377 [
52f09320 2378 'time' => $afterFirstUnit->format('Y-m-d H:i:s'),
9099cab3
CW
2379 'recipients' => [["test-member-{$interval_unit}@example.com"]],
2380 ],
2381 ];
52f09320
PH
2382 $this->assertCronRuns($cronRuns);
2383 $actionSchedule->delete();
2384 $membership->delete();
2385 }
2386 }
2387
bb3ba83e
AH
2388 /**
2389 * Inherited members without permission to edit the main member contact should
2390 * not get reminders.
2391 *
2392 * However, just because a contact inherits one membership doesn't mean
2393 * reminders for other memberships should be suppressed.
2394 *
2395 * See CRM-14098
34662dda 2396 *
2397 * @throws \CRM_Core_Exception
bb3ba83e
AH
2398 */
2399 public function testInheritedMembershipPermissions() {
2400 // Set up common parameters for memberships.
2401 $membershipParams = $this->fixtures['rolling_membership'];
2402 $membershipParams['status_id'] = 1;
2403
2404 $membershipParams['membership_type_id']['relationship_type_id'] = 1;
2405 $membershipParams['membership_type_id']['relationship_direction'] = 'b_a';
2406 $membershipType1 = $this->createTestObject('CRM_Member_DAO_MembershipType', $membershipParams['membership_type_id']);
2407
2408 // We'll create a new membership type that can be held at the same time as
2409 // the first one.
2410 $membershipParams['membership_type_id']['relationship_type_id'] = 'NULL';
2411 $membershipParams['membership_type_id']['relationship_direction'] = 'NULL';
2412 $membershipType2 = $this->createTestObject('CRM_Member_DAO_MembershipType', $membershipParams['membership_type_id']);
2413
2414 // Create the parent membership and contact
2415 $membershipParams['membership_type_id'] = $membershipType1->id;
2416 $mainMembership = $this->createTestObject('CRM_Member_DAO_Membership', $membershipParams);
2417
2418 $contactParams = [
2419 'contact_type' => 'Individual',
2420 'first_name' => 'Mom',
2421 'last_name' => 'Rel',
2422 'is_deceased' => 0,
2423 ];
2424 $this->createTestObject('CRM_Contact_DAO_Contact', array_merge($contactParams, ['id' => $mainMembership->contact_id]));
2425
2426 $emailParams = [
2427 'contact_id' => $mainMembership->contact_id,
2428 'email' => 'test-member@example.com',
2429 'location_type_id' => 1,
2430 'is_primary' => 1,
2431 ];
34662dda 2432 $this->createTestObject('CRM_Core_DAO_Email', $emailParams);
bb3ba83e
AH
2433
2434 // Set up contacts and emails for the two children
2435 $contactParams['first_name'] = 'Favorite';
2436 $permChild = $this->createTestObject('CRM_Contact_DAO_Contact', $contactParams);
2437 $emailParams['email'] = 'favorite@example.com';
2438 $emailParams['contact_id'] = $permChild->id;
2439 $this->createTestObject('CRM_Core_DAO_Email', $emailParams);
2440
2441 $contactParams['first_name'] = 'Black Sheep';
2442 $nonPermChild = $this->createTestObject('CRM_Contact_DAO_Contact', $contactParams);
2443 $emailParams['email'] = 'black.sheep@example.com';
2444 $emailParams['contact_id'] = $nonPermChild->id;
2445 $this->createTestObject('CRM_Core_DAO_Email', $emailParams);
2446
2447 // Each child gets a relationship, one with permission to edit the parent. This
2448 // will trigger inherited memberships for the first membership type
2449 $relParams = [
2450 'relationship_type_id' => 1,
2451 'contact_id_a' => $nonPermChild->id,
2452 'contact_id_b' => $mainMembership->contact_id,
2453 'is_active' => 1,
2454 ];
2455 $this->callAPISuccess('relationship', 'create', $relParams);
2456
2457 $relParams['contact_id_a'] = $permChild->id;
2458 $relParams['is_permission_a_b'] = CRM_Contact_BAO_Relationship::EDIT;
2459 $this->callAPISuccess('relationship', 'create', $relParams);
2460
2461 // Mom and Black Sheep get their own memberships of the second type.
2462 $membershipParams['membership_type_id'] = $membershipType2->id;
2463 $membershipParams['owner_membership_id'] = 'NULL';
2464 $membershipParams['contact_id'] = $mainMembership->contact_id;
2465 $this->createTestObject('CRM_Member_DAO_Membership', $membershipParams);
2466
2467 $membershipParams['contact_id'] = $nonPermChild->id;
2468 $this->createTestObject('CRM_Member_DAO_Membership', $membershipParams);
2469
2470 // Test a reminder for the first membership type - that should exclude Black
2471 // Sheep.
2472 $actionSchedule = $this->fixtures['sched_membership_join_2week'];
2473 $actionSchedule['entity_value'] = $membershipType1->id;
2474 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
2475 $this->assertTrue(is_numeric($actionScheduleDao->id));
2476
2477 $this->assertCronRuns([
2478 [
2479 'time' => '2012-03-29 01:00:00',
2480 'recipients' => [['test-member@example.com'], ['favorite@example.com']],
2481 'subjects' => [
2482 'subject sched_membership_join_2week (joined March 15th, 2012)',
2483 'subject sched_membership_join_2week (joined March 15th, 2012)',
2484 ],
2485 ],
2486 ]);
2487
2488 // Test a reminder for the second membership type - that should include
2489 // Black Sheep.
2490 $actionSchedule = $this->fixtures['sched_membership_start_1week'];
2491 $actionSchedule['entity_value'] = $membershipType2->id;
2492 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 2493 $this->assertInternalType('numeric', $actionScheduleDao->id);
bb3ba83e
AH
2494
2495 $this->assertCronRuns([
2496 [
2497 'time' => '2012-03-22 01:00:00',
2498 'recipients' => [['test-member@example.com'], ['black.sheep@example.com']],
2499 'subjects' => [
2500 'subject sched_membership_start_1week (joined March 15th, 2012)',
2501 'subject sched_membership_start_1week (joined March 15th, 2012)',
2502 ],
2503 ],
2504 ]);
2505 }
2506
34662dda 2507 /**
2508 * Modify the date time by the modify rule.
2509 *
2510 * @param DateTime $origDateTime
2511 * @param string $modifyRule
2512 *
2513 * @return DateTime
2514 */
52f09320
PH
2515 public function createModifiedDateTime($origDateTime, $modifyRule) {
2516 $newDateTime = clone($origDateTime);
2517 $newDateTime->modify($modifyRule);
2518 return $newDateTime;
2519 }
2520
34662dda 2521 /**
2522 * Test absolute date handling for membership.
2523 *
2524 * @throws \CRM_Core_Exception
2525 */
e08fae02 2526 public function testMembershipScheduleWithAbsoluteDate() {
34662dda 2527 $membership = $this->createMembershipFromFixture('rolling_membership', 'New', [
e08fae02
PH
2528 'email' => 'test-member@example.com',
2529 'location_type_id' => 1,
9099cab3 2530 ]);
e08fae02 2531
9099cab3 2532 $this->callAPISuccess('contact', 'create', array_merge($this->fixtures['contact'], ['contact_id' => $membership->contact_id]));
e08fae02
PH
2533 $actionSchedule = $this->fixtures['sched_membership_absolute_date'];
2534 $actionSchedule['entity_value'] = $membership->membership_type_id;
2535 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($actionSchedule);
34662dda 2536 $this->assertInternalType('numeric', $actionScheduleDao->id);
e08fae02 2537
9099cab3
CW
2538 $this->assertCronRuns([
2539 [
e08fae02
PH
2540 // Before the 24-hour mark, no email
2541 'time' => '2012-06-13 04:00:00',
9099cab3
CW
2542 'recipients' => [],
2543 'subjects' => [],
2544 ],
2545 [
e08fae02
PH
2546 // On absolute date set on 2012-06-14
2547 'time' => '2012-06-14 00:00:00',
9099cab3
CW
2548 'recipients' => [['test-member@example.com']],
2549 'subjects' => ['subject sched_membership_absolute_date'],
2550 ],
2551 [
e08fae02
PH
2552 // Run cron 4 hours later; first message already sent
2553 'time' => '2012-06-14 04:00:00',
9099cab3
CW
2554 'recipients' => [],
2555 'subjects' => [],
2556 ],
2557 ]);
e08fae02
PH
2558 }
2559
34662dda 2560 /**
2561 * @param string $fixture
2562 * Key from $this->fixtures
2563 * @param string $status
2564 * Membership status
2565 * @param array $emailParams
2566 *
2567 * @return \CRM_Member_DAO_Membership
2568 * @throws \API_Exception
2569 * @throws \Civi\API\Exception\UnauthorizedException
2570 */
2571 protected function createMembershipFromFixture($fixture, $status, $emailParams = []) {
2572 /* @var CRM_Member_DAO_Membership $membership */
2573 $membership = $this->createTestObject(
2574 'CRM_Member_DAO_Membership',
2575 array_merge($this->fixtures[$fixture], ['status_id' => CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', $status)])
2576 );
2577 $this->assertInternalType('numeric', $membership->id);
2578 if ($emailParams) {
2579 Civi\Api4\Email::create()->setCheckPermissions(FALSE)->setValues(array_merge([
2580 'contact_id' => $membership->contact_id,
2581 'location_type_id' => 1,
2582 ], $emailParams))->execute();
2583 }
2584 return $membership;
2585 }
2586
2587 /**
2588 * Create action schedule from defined fixtures.
2589 *
2590 * @param string $fixture
2591 */
2592 protected function createScheduleFromFixtures($fixture) {
2593 $actionScheduleDao = CRM_Core_BAO_ActionSchedule::add($this->fixtures[$fixture]);
2594 $this->assertInternalType('numeric', $actionScheduleDao->id);
2595 }
2596
6a488035 2597}