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