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