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