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