Merge pull request #23226 from MegaphoneJon/individual-employers
[civicrm-core.git] / CRM / Event / Form / ManageEvent / Registration.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
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
TO
11
12/**
6a488035 13 * @package CRM
ca5cec67 14 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
15 */
16
17/**
3bdf1f3a 18 * This class generates form components for processing Event.
6a488035
TO
19 */
20class CRM_Event_Form_ManageEvent_Registration extends CRM_Event_Form_ManageEvent {
21
22 /**
100fef9d 23 * What blocks should we show and hide.
6a488035
TO
24 *
25 * @var CRM_Core_ShowHideBlocks
26 */
27 protected $_showHide;
28
be2fb01f
CW
29 protected $_profilePostMultiple = [];
30 protected $_profilePostMultipleAdd = [];
6a488035
TO
31
32 /**
66f9e52b 33 * Set variables up before form is built.
f55dc004 34 */
00be9182 35 public function preProcess() {
6a488035
TO
36 $this->_addProfileBottom = CRM_Utils_Array::value('addProfileBottom', $_GET, FALSE);
37 $this->_profileBottomNum = CRM_Utils_Array::value('addProfileNum', $_GET, 0);
38 $this->_addProfileBottomAdd = CRM_Utils_Array::value('addProfileBottomAdd', $_GET, FALSE);
39 $this->_profileBottomNumAdd = CRM_Utils_Array::value('addProfileNumAdd', $_GET, 0);
40
41 parent::preProcess();
e4b857f8 42 $this->setSelectedChild('registration');
6a488035
TO
43
44 $this->assign('addProfileBottom', $this->_addProfileBottom);
45 $this->assign('profileBottomNum', $this->_profileBottomNum);
46
47 $urlParams = "id={$this->_id}&addProfileBottom=1&qfKey={$this->controller->_key}";
48 $this->assign('addProfileParams', $urlParams);
49
50 if ($addProfileBottom = CRM_Utils_Array::value('custom_post_id_multiple', $_POST)) {
51 foreach (array_keys($addProfileBottom) as $profileNum) {
52 self::buildMultipleProfileBottom($this, $profileNum);
53 }
54 }
55
56 $this->assign('addProfileBottomAdd', $this->_addProfileBottomAdd);
57 $this->assign('profileBottomNumAdd', $this->_profileBottomNumAdd);
58
59 $urlParamsAdd = "id={$this->_id}&addProfileBottomAdd=1&qfKey={$this->controller->_key}";
60 $this->assign('addProfileParamsAdd', $urlParamsAdd);
61
62 if ($addProfileBottomAdd = CRM_Utils_Array::value('additional_custom_post_id_multiple', $_POST)) {
63 foreach (array_keys($addProfileBottomAdd) as $profileNum) {
64 self::buildMultipleProfileBottom($this, $profileNum, 'additional_', ts('Profile for Additional Participants'));
65 }
66 }
67 }
68
69 /**
c490a46a 70 * Set default values for the form.
6a488035 71 *
3bdf1f3a 72 * The default values are retrieved from the database.
6a488035 73 */
00be9182 74 public function setDefaultValues() {
6a488035
TO
75 if ($this->_addProfileBottom || $this->_addProfileBottomAdd) {
76 return;
77 }
78 $eventId = $this->_id;
79
80 $defaults = parent::setDefaultValues();
81
82 $this->setShowHide($defaults);
83 if (isset($eventId)) {
be2fb01f 84 $params = ['id' => $eventId];
6a488035
TO
85 CRM_Event_BAO_Event::retrieve($params, $defaults);
86
be2fb01f 87 $ufJoinParams = [
6a488035
TO
88 'entity_table' => 'civicrm_event',
89 'module' => 'CiviEvent',
90 'entity_id' => $eventId,
be2fb01f 91 ];
6a488035
TO
92
93 list($defaults['custom_pre_id'],
94 $defaults['custom_post']
353ffa53 95 ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams);
6a488035
TO
96
97 // Get the id for the event registration profile
be2fb01f 98 $eventRegistrationIdParams = $eventRegistrationIdDefaults = [
6a488035 99 'name' => 'event_registration',
be2fb01f 100 ];
6a488035
TO
101 CRM_Core_BAO_UFGroup::retrieve($eventRegistrationIdParams, $eventRegistrationIdDefaults);
102
103 // Set event registration as the default profile if none selected
104 if (!$defaults['custom_pre_id'] && count($defaults['custom_post']) == 0) {
9c1bc317 105 $defaults['custom_pre_id'] = $eventRegistrationIdDefaults['id'] ?? NULL;
6a488035
TO
106 }
107 if (isset($defaults['custom_post']) && is_numeric($defaults['custom_post'])) {
108 $defaults['custom_post_id'] = $defaults['custom_post'];
109 }
110 elseif (!empty($defaults['custom_post'])) {
111 $defaults['custom_post_id'] = $defaults['custom_post'][0];
112 unset($defaults['custom_post'][0]);
113 $this->_profilePostMultiple = $defaults['custom_post'];
114 foreach ($defaults['custom_post'] as $key => $value) {
115 self::buildMultipleProfileBottom($this, $key);
116 $defaults["custom_post_id_multiple[$key]"] = $value;
117 }
118 }
119
120 $this->assign('profilePostMultiple', CRM_Utils_Array::value('custom_post', $defaults));
121
f1bc01e0
J
122 // CRM-17745: Make max additional participants configurable
123 if (empty($defaults['max_additional_participants'])) {
124 $defaults['max_additional_participants'] = 9;
125 }
126
a7488080 127 if (!empty($defaults['is_multiple_registrations'])) {
6a488035 128 // CRM-4377: set additional participants’ profiles – set to ‘none’ if explicitly unset (non-active)
be2fb01f 129 $ufJoinAddParams = [
6a488035
TO
130 'entity_table' => 'civicrm_event',
131 'module' => 'CiviEvent_Additional',
132 'entity_id' => $eventId,
be2fb01f 133 ];
6a488035
TO
134
135 list($defaults['additional_custom_pre_id'],
136 $defaults['additional_custom_post']
353ffa53 137 ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinAddParams);
6a488035
TO
138
139 if (isset($defaults['additional_custom_post']) && is_numeric($defaults['additional_custom_post'])) {
140 $defaults['additional_custom_post_id'] = $defaults['additional_custom_post'];
141 }
142 elseif (!empty($defaults['additional_custom_post'])) {
143 $defaults['additional_custom_post_id'] = $defaults['additional_custom_post'][0];
144 unset($defaults['additional_custom_post'][0]);
145
146 $this->_profilePostMultipleAdd = $defaults['additional_custom_post'];
147 foreach ($defaults['additional_custom_post'] as $key => $value) {
148 self::buildMultipleProfileBottom($this, $key, 'additional_', ts('Profile for Additional Participants'));
149 $defaults["additional_custom_post_id_multiple[$key]"] = $value;
150 }
151 }
d52d6838 152 $this->assign('profilePostMultipleAdd', CRM_Utils_Array::value('additional_custom_post', $defaults, []));
6a488035 153 }
1467e70c
ML
154 else {
155 // Avoid PHP notices in the template
156 $this->assign('profilePostMultipleAdd', []);
157 }
6a488035
TO
158 }
159 else {
160 $defaults['is_email_confirm'] = 0;
161 }
162
163 // provide defaults for required fields if empty (and as a 'hint' for approval message field)
164 $defaults['registration_link_text'] = CRM_Utils_Array::value('registration_link_text', $defaults, ts('Register Now'));
165 $defaults['confirm_title'] = CRM_Utils_Array::value('confirm_title', $defaults, ts('Confirm Your Registration Information'));
166 $defaults['thankyou_title'] = CRM_Utils_Array::value('thankyou_title', $defaults, ts('Thank You for Registering'));
167 $defaults['approval_req_text'] = CRM_Utils_Array::value('approval_req_text', $defaults, ts('Participation in this event requires approval. Submit your registration request here. Once approved, you will receive an email with a link to a web page where you can complete the registration process.'));
168
6a488035
TO
169 return $defaults;
170 }
171
172 /**
173 * Fix what blocks to show/hide based on the default values set
174 *
d4dd1e85
TO
175 * @param array $defaults
176 * The array of default values.
77b97be7 177 *
6a488035
TO
178 * @return void
179 */
00be9182 180 public function setShowHide($defaults) {
be2fb01f 181 $this->_showHide = new CRM_Core_ShowHideBlocks(['registration' => 1],
6a488035
TO
182 ''
183 );
184 if (empty($defaults)) {
185 $this->_showHide->addHide('registration');
6a488035
TO
186 $this->_showHide->addHide('id-approval-text');
187 }
188 else {
a7488080 189 if (empty($defaults['requires_approval'])) {
6a488035
TO
190 $this->_showHide->addHide('id-approval-text');
191 }
192 }
193 $this->assign('defaultsEmpty', empty($defaults));
194 $this->_showHide->addToTemplate();
195 }
196
197 /**
66f9e52b 198 * Build the form object.
6a488035 199 *
355ba699 200 * @return void
6a488035
TO
201 */
202 public function buildQuickForm() {
203 if ($this->_addProfileBottom) {
204 return self::buildMultipleProfileBottom($this, $this->_profileBottomNum);
205 }
206
207 if ($this->_addProfileBottomAdd) {
208 return self::buildMultipleProfileBottom($this, $this->_profileBottomNumAdd, 'additional_', ts('Profile for Additional Participants'));
209 }
210
211 $this->applyFilter('__ALL__', 'trim');
212 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
213
214 $this->addElement('checkbox',
215 'is_online_registration',
0781df9b 216 ts('Allow Online Registration'),
6a488035 217 NULL,
be2fb01f 218 [
d5cc0fc2 219 'onclick' => "return showHideByValue('is_online_registration'," .
220 "''," .
221 "'registration_blocks'," .
222 "'block'," .
223 "'radio'," .
224 "false );",
be2fb01f 225 ]
6a488035
TO
226 );
227
228 $this->add('text', 'registration_link_text', ts('Registration Link Text'));
229
230 if (!$this->_isTemplate) {
be2fb01f
CW
231 $this->add('datepicker', 'registration_start_date', ts('Registration Start Date'), [], FALSE, ['time' => TRUE]);
232 $this->add('datepicker', 'registration_end_date', ts('Registration End Date'), [], FALSE, ['time' => TRUE]);
6a488035
TO
233 }
234
be2fb01f 235 $params = [
353ffa53 236 'used' => 'Supervised',
6a488035 237 'contact_type' => 'Individual',
be2fb01f 238 ];
61194d45 239 $dedupeRuleFields = CRM_Dedupe_BAO_DedupeRule::dedupeRuleFields($params);
6a488035
TO
240
241 foreach ($dedupeRuleFields as $key => $fields) {
242 $ruleFields[$key] = ucwords(str_replace('_', ' ', $fields));
243 }
244
245 $this->addElement('checkbox',
246 'is_multiple_registrations',
b01353b5 247 ts('Register multiple participants?')
6a488035
TO
248 );
249
f1bc01e0
J
250 // CRM-17745: Make maximum additional participants configurable
251 $numericOptions = CRM_Core_SelectValues::getNumericOptions(1, 9);
be2fb01f 252 $this->add('select', 'max_additional_participants', ts('Maximum additional participants'), $numericOptions, FALSE, ['class' => 'required']);
f1bc01e0 253
6a488035
TO
254 $this->addElement('checkbox',
255 'allow_same_participant_emails',
03390e26 256 ts('Same email address?')
6a488035
TO
257 );
258 $this->assign('ruleFields', json_encode($ruleFields));
259
be2fb01f 260 $dedupeRules = [
fbaf3c7d 261 '' => ts('- Unsupervised rule -'),
be2fb01f 262 ];
61194d45 263 $dedupeRules += CRM_Dedupe_BAO_DedupeRuleGroup::getByType('Individual');
03390e26 264 $this->add('select', 'dedupe_rule_group_id', ts('Duplicate matching rule'), $dedupeRules);
265
6a488035
TO
266 $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
267 if (in_array('Awaiting approval', $participantStatuses) and in_array('Pending from approval', $participantStatuses) and in_array('Rejected', $participantStatuses)) {
268 $this->addElement('checkbox',
269 'requires_approval',
270 ts('Require participant approval?'),
271 NULL,
be2fb01f 272 ['onclick' => "return showHideByValue('requires_approval', '', 'id-approval-text', 'table-row', 'radio', false);"]
6a488035
TO
273 );
274 $this->add('textarea', 'approval_req_text', ts('Approval message'), $attributes['approval_req_text']);
275 }
276
277 $this->add('text', 'expiration_time', ts('Pending participant expiration (hours)'));
278 $this->addRule('expiration_time', ts('Please enter the number of hours (as an integer).'), 'integer');
be2fb01f 279 $this->addField('allow_selfcancelxfer', ['label' => ts('Allow self-service cancellation or transfer?'), 'type' => 'advcheckbox']);
adaa01fa 280 $this->add('text', 'selfcancelxfer_time', ts('Cancellation or transfer time limit (hours)'));
97d8187a 281 $this->addRule('selfcancelxfer_time', ts('Please enter the number of hours (as an integer).'), 'integer');
6a488035
TO
282 self::buildRegistrationBlock($this);
283 self::buildConfirmationBlock($this);
284 self::buildMailBlock($this);
285 self::buildThankYouBlock($this);
286
287 parent::buildQuickForm();
288 }
289
290 /**
66f9e52b 291 * Build Registration Block.
6a488035 292 *
c490a46a 293 * @param CRM_Core_Form $form
da6b46f4 294 *
6a488035 295 */
00be9182 296 public function buildRegistrationBlock(&$form) {
be2fb01f 297 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event', 'intro_text') + ['class' => 'collapsed', 'preset' => 'civievent'];
5d51a2f9
CW
298 $form->add('wysiwyg', 'intro_text', ts('Introductory Text'), $attributes);
299 $form->add('wysiwyg', 'footer_text', ts('Footer Text'), $attributes);
6a488035 300
481a74f4 301 extract(self::getProfileSelectorTypes());
99e239bc 302 //CRM-15427
37375016 303 $form->addProfileSelector('custom_pre_id', ts('Include Profile') . '<br />' . ts('(top of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE, $usedFor);
304 $form->addProfileSelector('custom_post_id', ts('Include Profile') . '<br />' . ts('(bottom of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE, $usedFor);
6a488035 305
37375016 306 $form->addProfileSelector('additional_custom_pre_id', ts('Profile for Additional Participants') . '<br />' . ts('(top of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE, $usedFor);
307 $form->addProfileSelector('additional_custom_post_id', ts('Profile for Additional Participants') . '<br />' . ts('(bottom of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE, $usedFor);
6a488035
TO
308 }
309
8e8a3d81 310 /**
66f9e52b 311 * Subroutine to insert a Profile Editor widget.
8e8a3d81 312 * depends on getProfileSelectorTypes
03390e26 313 *
64f4eebe 314 * @param \CRM_Core_Form &$form
d4dd1e85
TO
315 * @param int $count
316 * Unique index.
317 * @param string $prefix
318 * Dom element ID prefix.
319 * @param string $label
320 * Label.
321 * @param array $configs
322 * Optional, for addProfileSelector(), defaults to using getProfileSelectorTypes().
a130e045 323 */
59e3294d 324 public static function buildMultipleProfileBottom(&$form, $count, $prefix = '', $label = 'Include Profile', $configs = NULL) {
481a74f4 325 extract((is_null($configs)) ? self::getProfileSelectorTypes() : $configs);
518ef837 326 $element = $prefix . "custom_post_id_multiple[$count]";
92fcb95f 327 $label .= '<br />' . ts('(bottom of page)');
37375016 328 $form->addProfileSelector($element, $label, $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE, $usedFor);
518ef837 329 }
330
8e8a3d81 331 /**
66f9e52b 332 * Create initializers for addprofileSelector.
8e8a3d81 333 *
72b3a70c
CW
334 * @return array
335 * ['allowCoreTypes' => array, 'allowSubTypes' => array, 'profileEntities' => array]
a130e045 336 */
00be9182 337 public static function getProfileSelectorTypes() {
be2fb01f
CW
338 $configs = [
339 'allowCoreTypes' => [],
340 'allowSubTypes' => [],
341 'profileEntities' => [],
342 'usedFor' => [],
343 ];
344
345 $configs['allowCoreTypes'] = array_merge([
90b461f1
SL
346 'Contact',
347 'Individual',
348 ], CRM_Contact_BAO_ContactType::subTypes('Individual'));
518ef837 349 $configs['allowCoreTypes'][] = 'Participant';
37375016 350 if (CRM_Core_Permission::check('manage event profiles') && !CRM_Core_Permission::check('administer CiviCRM')) {
351 $configs['usedFor'][] = 'CiviEvent';
352 }
99e239bc 353 //CRM-15427
481a74f4 354 $id = CRM_Utils_Request::retrieve('id', 'Integer');
0b1c947e 355 if ($id) {
efd9f169 356 $participantEventType = CRM_Core_DAO::getFieldValue("CRM_Event_DAO_Event", $id, 'event_type_id', 'id');
353ffa53 357 $participantRole = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $id, 'default_role_id');
be2fb01f
CW
358 $configs['allowSubTypes']['ParticipantEventName'] = [$id];
359 $configs['allowSubTypes']['ParticipantEventType'] = [$participantEventType];
360 $configs['allowSubTypes']['ParticipantRole'] = [$participantRole];
f80ef0e2 361 }
be2fb01f
CW
362 $configs['profileEntities'][] = ['entity_name' => 'contact_1', 'entity_type' => 'IndividualModel'];
363 $configs['profileEntities'][] = [
353ffa53
TO
364 'entity_name' => 'participant_1',
365 'entity_type' => 'ParticipantModel',
a130e045 366 'entity_sub_type' => '*',
be2fb01f 367 ];
6a488035 368
0479b4c8 369 return $configs;
6a488035
TO
370 }
371
372 /**
66f9e52b 373 * Build Confirmation Block.
6a488035 374 *
c490a46a 375 * @param CRM_Core_Form $form
2a6da8d7 376 *
6a488035 377 */
00be9182 378 public function buildConfirmationBlock(&$form) {
6a488035 379 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
d6121d3e 380 // CRM-11182 - Optional confirmation page for free events
381 $is_monetary = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $form->_id, 'is_monetary');
382 $form->assign('is_monetary', $is_monetary);
383 if ($is_monetary == "0") {
be2fb01f 384 $form->addYesNo('is_confirm_enabled', ts('Use a confirmation screen?'), NULL, NULL, ['onclick' => "return showHideByValue('is_confirm_enabled','','confirm_screen_settings','block','radio',false);"]);
d6121d3e 385 }
6a488035 386 $form->add('text', 'confirm_title', ts('Title'), $attributes['confirm_title']);
be2fb01f
CW
387 $form->add('wysiwyg', 'confirm_text', ts('Introductory Text'), $attributes['confirm_text'] + ['class' => 'collapsed', 'preset' => 'civievent']);
388 $form->add('wysiwyg', 'confirm_footer_text', ts('Footer Text'), $attributes['confirm_text'] + ['class' => 'collapsed', 'preset' => 'civievent']);
6a488035
TO
389 }
390
391 /**
66f9e52b 392 * Build Email Block.
6a488035 393 *
c490a46a 394 * @param CRM_Core_Form $form
6a488035 395 */
00be9182 396 public function buildMailBlock(&$form) {
6a488035
TO
397 $form->registerRule('emailList', 'callback', 'emailList', 'CRM_Utils_Rule');
398 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
be2fb01f 399 $form->addYesNo('is_email_confirm', ts('Send Confirmation Email?'), NULL, NULL, ['onclick' => "return showHideByValue('is_email_confirm','','confirmEmail','block','radio',false);"]);
6a488035
TO
400 $form->add('textarea', 'confirm_email_text', ts('Text'), $attributes['confirm_email_text']);
401 $form->add('text', 'cc_confirm', ts('CC Confirmation To'), CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event', 'cc_confirm'));
402 $form->addRule('cc_confirm', ts('Please enter a valid list of comma delimited email addresses'), 'emailList');
403 $form->add('text', 'bcc_confirm', ts('BCC Confirmation To'), CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event', 'bcc_confirm'));
404 $form->addRule('bcc_confirm', ts('Please enter a valid list of comma delimited email addresses'), 'emailList');
405 $form->add('text', 'confirm_from_name', ts('Confirm From Name'));
406 $form->add('text', 'confirm_from_email', ts('Confirm From Email'));
407 $form->addRule('confirm_from_email', ts('Email is not valid.'), 'email');
408 }
409
0cf587a7 410 /**
c490a46a 411 * @param CRM_Core_Form $form
0cf587a7 412 */
00be9182 413 public function buildThankYouBlock(&$form) {
6a488035
TO
414 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
415 $form->add('text', 'thankyou_title', ts('Title'), $attributes['thankyou_title']);
be2fb01f
CW
416 $form->add('wysiwyg', 'thankyou_text', ts('Introductory Text'), $attributes['thankyou_text'] + ['class' => 'collapsed', 'preset' => 'civievent']);
417 $form->add('wysiwyg', 'thankyou_footer_text', ts('Footer Text'), $attributes['thankyou_text'] + ['class' => 'collapsed', 'preset' => 'civievent']);
6a488035
TO
418 }
419
420 /**
66f9e52b 421 * Add local and global form rules.
6a488035 422 *
6a488035
TO
423 * @return void
424 */
00be9182 425 public function addRules() {
6a488035
TO
426 if ($this->_addProfileBottom || $this->_addProfileBottomAdd) {
427 return;
428 }
be2fb01f 429 $this->addFormRule(['CRM_Event_Form_ManageEvent_Registration', 'formRule'], $this);
6a488035
TO
430 }
431
432 /**
66f9e52b 433 * Global validation rules for the form.
6a488035 434 *
c490a46a 435 * @param array $values
2a6da8d7 436 * @param $files
c490a46a 437 * @param CRM_Core_Form $form
6a488035 438 *
a6c01b45
CW
439 * @return array
440 * list of errors to be posted back to the form
6a488035 441 */
00be9182 442 public static function formRule($values, $files, $form) {
a7488080 443 if (!empty($values['is_online_registration'])) {
6a488035
TO
444
445 if (!$values['confirm_title']) {
446 $errorMsg['confirm_title'] = ts('Please enter a Title for the registration Confirmation Page');
447 }
448 if (!$values['thankyou_title']) {
449 $errorMsg['thankyou_title'] = ts('Please enter a Title for the registration Thank-you Page');
450 }
451 if ($values['is_email_confirm']) {
452 if (!$values['confirm_from_name']) {
453 $errorMsg['confirm_from_name'] = ts('Please enter Confirmation Email FROM Name.');
454 }
455
456 if (!$values['confirm_from_email']) {
457 $errorMsg['confirm_from_email'] = ts('Please enter Confirmation Email FROM Email Address.');
458 }
459 }
f55dc004 460
c03ba827
MWMC
461 if (isset($values['registration_start_date']) && isset($values['registration_end_date'])) {
462 if ($values['registration_end_date'] < $values['registration_start_date']) {
6a488035
TO
463 $errorMsg['registration_end_date'] = ts('Registration end date should be after Registration start date');
464 }
465 }
466
467 //check that the selected profiles have either firstname+lastname or email required
be2fb01f 468 $profileIds = [
6a488035
TO
469 CRM_Utils_Array::value('custom_pre_id', $values),
470 CRM_Utils_Array::value('custom_post_id', $values),
be2fb01f
CW
471 ];
472 $additionalProfileIds = [
6a488035
TO
473 CRM_Utils_Array::value('additional_custom_pre_id', $values),
474 CRM_Utils_Array::value('additional_custom_post_id', $values),
be2fb01f 475 ];
6a488035
TO
476 //additional profile fields default to main if not set
477 if (!is_numeric($additionalProfileIds[0])) {
478 $additionalProfileIds[0] = $profileIds[0];
479 }
480 if (!is_numeric($additionalProfileIds[1])) {
481 $additionalProfileIds[1] = $profileIds[1];
482 }
483 //add multiple profiles if set
484 self::addMultipleProfiles($profileIds, $values, 'custom_post_id_multiple');
485 self::addMultipleProfiles($additionalProfileIds, $values, 'additional_custom_post_id_multiple');
486 $isProfileComplete = self::isProfileComplete($profileIds);
487 $isAdditionalProfileComplete = self::isProfileComplete($additionalProfileIds);
03390e26 488
6a488035
TO
489 //Check main profiles have an email address available if 'send confirmation email' is selected
490 if ($values['is_email_confirm']) {
491 $emailFields = self::getEmailFields($profileIds);
492 if (!count($emailFields)) {
493 $errorMsg['is_email_confirm'] = ts("Please add a profile with an email address if 'Send Confirmation Email?' is selected");
494 }
495 }
496 $additionalCustomPreId = $additionalCustomPostId = NULL;
497 $isPreError = $isPostError = TRUE;
8cc574cf 498 if (!empty($values['allow_same_participant_emails']) && !empty($values['is_multiple_registrations'])) {
be2fb01f 499 $types = array_merge(['Individual'], CRM_Contact_BAO_ContactType::subTypes('Individual'));
6a488035
TO
500 $profiles = CRM_Core_BAO_UFGroup::getProfiles($types);
501
502 //check for additional custom pre profile
9c1bc317 503 $additionalCustomPreId = $values['additional_custom_pre_id'] ?? NULL;
6a488035
TO
504 if (!empty($additionalCustomPreId)) {
505 if (!($additionalCustomPreId == 'none')) {
506 $customPreId = $additionalCustomPreId;
507 }
508 else {
509 $isPreError = FALSE;
510 }
511 }
512 else {
0d8afee2 513 $customPreId = !empty($values['custom_pre_id']) ? $values['custom_pre_id'] : NULL;
6a488035
TO
514 }
515 //check whether the additional custom pre profile is of type 'Individual' and its subtypes
516 if (!empty($customPreId)) {
517 $profileTypes = CRM_Core_BAO_UFGroup::profileGroups($customPreId);
518 foreach ($types as $individualTypes) {
519 if (in_array($individualTypes, $profileTypes)) {
520 $isPreError = FALSE;
521 break;
522 }
523 }
524 }
525 else {
526 $isPreError = FALSE;
527 }
f55dc004 528
dbeb7efb
DG
529 // We don't have required Individual fields in the pre-custom profile, so now check the post-custom profile
530 if ($isPreError) {
9c1bc317 531 $additionalCustomPostId = $values['additional_custom_post_id'] ?? NULL;
dbeb7efb
DG
532 if (!empty($additionalCustomPostId)) {
533 if (!($additionalCustomPostId == 'none')) {
534 $customPostId = $additionalCustomPostId;
535 }
536 else {
537 $isPostError = FALSE;
538 }
6a488035
TO
539 }
540 else {
0d8afee2 541 $customPostId = !empty($values['custom_post_id']) ? $values['custom_post_id'] : NULL;
6a488035 542 }
dbeb7efb
DG
543 //check whether the additional custom post profile is of type 'Individual' and its subtypes
544 if (!empty($customPostId)) {
545 $profileTypes = CRM_Core_BAO_UFGroup::profileGroups($customPostId);
546 foreach ($types as $individualTypes) {
547 if (in_array($individualTypes, $profileTypes)) {
548 $isPostError = FALSE;
549 break;
550 }
6a488035
TO
551 }
552 }
dbeb7efb
DG
553 else {
554 $isPostError = FALSE;
555 }
556
557 if (empty($customPreId) && empty($customPostId)) {
558 $errorMsg['additional_custom_pre_id'] = ts("Allow multiple registrations from the same email address requires a profile of type 'Individual'");
559 }
560 if ($isPostError) {
561 $errorMsg['additional_custom_post_id'] = ts("Allow multiple registrations from the same email address requires a profile of type 'Individual'");
562 }
6a488035
TO
563 }
564 }
565 if (!$isProfileComplete) {
566 $errorMsg['custom_pre_id'] = ts("Please include a Profile for online registration that contains an Email Address field and / or First Name + Last Name fields.");
567 }
568 if (!$isAdditionalProfileComplete) {
569 $errorMsg['additional_custom_pre_id'] = ts("Please include a Profile for online registration of additional participants that contains an Email Address field and / or First Name + Last Name fields.");
570 }
571
572 // // CRM-8485
573 // $config = CRM_Core_Config::singleton();
574 // if ( $config->doNotAttachPDFReceipt ) {
a7488080 575 // if (!empty($values['custom_post_id_multiple'])) {
6a488035
TO
576 // foreach( $values['custom_post_id_multiple'] as $count => $customPostMultiple ) {
577 // if ( $customPostMultiple ) {
578 // $errorMsg["custom_post_id_multiple[{$count}]"] = ts('Please disable PDF receipt as an attachment in <a href="%1">Miscellaneous Settings</a> if you want to add additional profiles.', array( 1 => CRM_Utils_System::url( 'civicrm/admin/setting/misc', 'reset=1' ) ) );
579 // break;
580 // }
581 // }
582 // }
583 //
a7488080 584 // if (!empty($values['is_multiple_registrations']) &&
6a488035
TO
585 // CRM_Utils_Array::value('additional_custom_post_id_multiple', $values) ) {
586 // foreach( $values['additional_custom_post_id_multiple'] as $count => $customPostMultiple ) {
587 // if ( $customPostMultiple ) {
588 // $errorMsg["additional_custom_post_id_multiple[{$count}]"] = ts('Please disable PDF receipt as an attachment in <a href="%1">Miscellaneous Settings</a> if you want to add additional profiles.', array( 1 => CRM_Utils_System::url( 'civicrm/admin/setting/misc', 'reset=1' ) ) );
589 // break;
590 // }
591 // }
592 // }
593 // }
594
595 if (!empty($errorMsg)) {
a7488080 596 if (!empty($values['custom_post_id_multiple'])) {
6a488035
TO
597 foreach ($values['custom_post_id_multiple'] as $count => $customPostMultiple) {
598 self::buildMultipleProfileBottom($form, $count);
599 }
600 $form->assign('profilePostMultiple', $values['custom_post_id_multiple']);
601 }
a7488080 602 if (!empty($values['additional_custom_post_id_multiple'])) {
6a488035
TO
603 foreach ($values['additional_custom_post_id_multiple'] as $count => $customPostMultiple) {
604 self::buildMultipleProfileBottom($form, $count, 'additional_', ts('Profile for Additional Participants'));
605 }
606 $form->assign('profilePostMultipleAdd', $values['additional_custom_post_id_multiple']);
607 }
608 }
609 }
610
611 if (!empty($errorMsg)) {
612 return $errorMsg;
613 }
614
615 return TRUE;
616 }
617
618 /**
66f9e52b 619 * Collect all email fields for an array of profile ids.
6a488035 620 *
2a6da8d7 621 * @param $profileIds
64f4eebe 622 * @return array
6a488035 623 */
00be9182 624 public static function getEmailFields($profileIds) {
be2fb01f 625 $emailFields = [];
6a488035
TO
626 foreach ($profileIds as $profileId) {
627 if ($profileId && is_numeric($profileId)) {
628 $fields = CRM_Core_BAO_UFGroup::getFields($profileId);
629 foreach ($fields as $field) {
630 if (substr_count($field['name'], 'email')) {
631 $emailFields[] = $field;
632 }
633 }
634 }
635 }
636 return $emailFields;
637 }
638
639 /**
66f9e52b 640 * Check if a profile contains required fields.
6a488035 641 *
2a6da8d7 642 * @param $profileIds
a130e045 643 * @return bool
6a488035 644 */
00be9182 645 public static function isProfileComplete($profileIds) {
be2fb01f 646 $profileReqFields = [];
6a488035
TO
647 foreach ($profileIds as $profileId) {
648 if ($profileId && is_numeric($profileId)) {
649 $fields = CRM_Core_BAO_UFGroup::getFields($profileId);
650 foreach ($fields as $field) {
651 switch (TRUE) {
652 case substr_count($field['name'], 'email'):
653 $profileReqFields[] = 'email';
654 break;
655
656 case substr_count($field['name'], 'first_name'):
657 $profileReqFields[] = 'first_name';
658 break;
659
660 case substr_count($field['name'], 'last_name'):
661 $profileReqFields[] = 'last_name';
662 break;
663 }
664 }
665 }
666 }
667 $profileComplete = (in_array('email', $profileReqFields)
668 || (in_array('first_name', $profileReqFields) && in_array('last_name', $profileReqFields))
669 );
670 return $profileComplete;
671 }
672
03390e26 673 /**
66f9e52b 674 * Check if the profiles collect enough information to dedupe.
03390e26 675 *
2a6da8d7
EM
676 * @param $profileIds
677 * @param int $rgId
a130e045 678 * @return bool
03390e26 679 */
60fbd968 680 public static function canProfilesDedupe($profileIds, $rgId = 0) {
03390e26 681 // find the unsupervised rule
be2fb01f 682 $rgParams = [
03390e26 683 'used' => 'Unsupervised',
684 'contact_type' => 'Individual',
be2fb01f 685 ];
03390e26 686 if ($rgId > 0) {
687 $rgParams['id'] = $rgId;
688 }
61194d45 689 $activeRg = CRM_Dedupe_BAO_DedupeRuleGroup::dedupeRuleFieldsWeight($rgParams);
03390e26 690
691 // get the combinations that could be a match for the rule
be2fb01f 692 $okCombos = $combos = [];
61194d45 693 CRM_Dedupe_BAO_DedupeRuleGroup::combos($activeRg[0], $activeRg[1], $combos);
03390e26 694
695 // create an index of what combinations involve each field
be2fb01f 696 $index = [];
03390e26 697 foreach ($combos as $comboid => $combo) {
698 foreach ($combo as $cfield) {
0479b4c8 699 $index[$cfield][$comboid] = TRUE;
03390e26 700 }
701 $combos[$comboid] = array_fill_keys($combo, 0);
702 $okCombos[$comboid] = array_fill_keys($combo, 2);
703 }
704
705 // get profiles and see if they have the necessary combos
be2fb01f 706 $profileReqFields = [];
03390e26 707 foreach ($profileIds as $profileId) {
708 if ($profileId && is_numeric($profileId)) {
709 $fields = CRM_Core_BAO_UFGroup::getFields($profileId);
710
711 // walk through the fields in the profile
712 foreach ($fields as $field) {
713
714 // check each of the fields in the index against the profile field
715 foreach ($index as $ifield => $icombos) {
22e263ad 716 if (strpos($field['name'], $ifield) !== FALSE) {
03390e26 717
718 // we found the field in the profile, now record it in the index
719 foreach ($icombos as $icombo => $dontcare) {
720 $combos[$icombo][$ifield] = ($combos[$icombo][$ifield] != 2 && !$field['is_required']) ? 1 : 2;
721
722 if ($combos[$icombo] == $okCombos[$icombo]) {
723 // if any combo is complete with 2s (all fields are present and required), we can go home
724 return 2;
725 }
726 }
727 }
728 }
729 }
730 }
731 }
732
733 // check the combos to see if everything is > 0
734 foreach ($combos as $comboid => $combo) {
0479b4c8 735 $complete = FALSE;
03390e26 736 foreach ($combo as $cfield) {
737 if ($cfield > 0) {
0479b4c8 738 $complete = TRUE;
03390e26 739 }
740 else {
741 // this combo isn't complete--skip to the next combo
742 continue 2;
743 }
744 }
4f99ca55
TO
745 if ($complete) {
746 return 1;
0479b4c8 747 }
03390e26 748 }
749
750 // no combo succeeded
751 return 0;
752 }
753
6a488035
TO
754 /**
755 * Add additional profiles from the form to an array of profile ids.
ad37ac8e 756 *
757 * @param array $profileIds
758 * @param array $values
759 * @param string $field
6a488035 760 */
00be9182 761 public static function addMultipleProfiles(&$profileIds, $values, $field) {
6a488035
TO
762 if ($multipleProfiles = CRM_Utils_Array::value($field, $values)) {
763 foreach ($multipleProfiles as $profileId) {
764 $profileIds[] = $profileId;
765 }
766 }
767 }
768
769 /**
66f9e52b 770 * Process the form submission.
6a488035 771 *
355ba699 772 * @return void
6a488035
TO
773 */
774 public function postProcess() {
6a488035
TO
775 $params = $this->exportValues();
776
777 $params['id'] = $this->_id;
778
1909126f 779 // format params
6a488035 780 $params['is_online_registration'] = CRM_Utils_Array::value('is_online_registration', $params, FALSE);
90b461f1
SL
781 // CRM-11182
782 $params['is_confirm_enabled'] = CRM_Utils_Array::value('is_confirm_enabled', $params, FALSE);
6a488035
TO
783 $params['is_multiple_registrations'] = CRM_Utils_Array::value('is_multiple_registrations', $params, FALSE);
784 $params['allow_same_participant_emails'] = CRM_Utils_Array::value('allow_same_participant_emails', $params, FALSE);
785 $params['requires_approval'] = CRM_Utils_Array::value('requires_approval', $params, FALSE);
786
787 // reset is_email confirm if not online reg
788 if (!$params['is_online_registration']) {
789 $params['is_email_confirm'] = FALSE;
790 }
4abc4ee1 791 if (!empty($params['allow_selfcancelxfer'])) {
792 $params['selfcancelxfer_time'] = !empty($params['selfcancelxfer_time']) ? $params['selfcancelxfer_time'] : 0;
793 }
6a488035 794
6a488035
TO
795 CRM_Event_BAO_Event::add($params);
796
797 // also update the ProfileModule tables
be2fb01f 798 $ufJoinParams = [
6a488035
TO
799 'is_active' => 1,
800 'module' => 'CiviEvent',
801 'entity_table' => 'civicrm_event',
802 'entity_id' => $this->_id,
be2fb01f 803 ];
6a488035 804
6a488035
TO
805 // first delete all past entries
806 CRM_Core_BAO_UFJoin::deleteAll($ufJoinParams);
807
be2fb01f 808 $uf = [];
6a488035
TO
809 $wt = 2;
810 if (!empty($params['custom_pre_id'])) {
811 $uf[1] = $params['custom_pre_id'];
812 $wt = 1;
813 }
814
815 if (!empty($params['custom_post_id'])) {
816 $uf[2] = $params['custom_post_id'];
817 }
818
a7488080 819 if (!empty($params['custom_post_id_multiple'])) {
6a488035
TO
820 $uf = array_merge($uf, $params['custom_post_id_multiple']);
821 }
822 $uf = array_values($uf);
823 if (!empty($uf)) {
824 foreach ($uf as $weight => $ufGroupId) {
825 $ufJoinParams['weight'] = $weight + $wt;
826 $ufJoinParams['uf_group_id'] = $ufGroupId;
827 CRM_Core_BAO_UFJoin::create($ufJoinParams);
828 unset($ufJoinParams['id']);
829 }
830 }
831 // also update the ProfileModule tables
be2fb01f 832 $ufJoinParamsAdd = [
6a488035
TO
833 'is_active' => 1,
834 'module' => 'CiviEvent_Additional',
835 'entity_table' => 'civicrm_event',
836 'entity_id' => $this->_id,
be2fb01f 837 ];
6a488035
TO
838
839 // first delete all past entries
840 CRM_Core_BAO_UFJoin::deleteAll($ufJoinParamsAdd);
a7488080 841 if (!empty($params['is_multiple_registrations'])) {
be2fb01f 842 $ufAdd = [];
6a488035
TO
843 $wtAdd = 2;
844
845 if (array_key_exists('additional_custom_pre_id', $params)) {
a7488080 846 if (empty($params['additional_custom_pre_id'])) {
6a488035
TO
847 $ufAdd[1] = $params['custom_pre_id'];
848 $wtAdd = 1;
849 }
353ffa53
TO
850 elseif (CRM_Utils_Array::value('additional_custom_pre_id', $params) == 'none') {
851 }
6a488035
TO
852 else {
853 $ufAdd[1] = $params['additional_custom_pre_id'];
854 $wtAdd = 1;
855 }
856 }
857
858 if (array_key_exists('additional_custom_post_id', $params)) {
a7488080 859 if (empty($params['additional_custom_post_id'])) {
6a488035
TO
860 $ufAdd[2] = $params['custom_post_id'];
861 }
353ffa53
TO
862 elseif (CRM_Utils_Array::value('additional_custom_post_id', $params) == 'none') {
863 }
6a488035
TO
864 else {
865 $ufAdd[2] = $params['additional_custom_post_id'];
866 }
867 }
868
a7488080 869 if (!empty($params['additional_custom_post_id_multiple'])) {
be2fb01f 870 $additionalPostMultiple = [];
6a488035 871 foreach ($params['additional_custom_post_id_multiple'] as $key => $value) {
85944a4e 872 if (is_null($value) && !empty($params['custom_post_id'])) {
6a488035
TO
873 $additionalPostMultiple[$key] = $params['custom_post_id'];
874 }
875 elseif ($value == 'none') {
876 continue;
877 }
878 elseif ($value) {
879 $additionalPostMultiple[$key] = $value;
880 }
881 }
882 $ufAdd = array_merge($ufAdd, $additionalPostMultiple);
883 }
884
885 $ufAdd = array_values($ufAdd);
886 if (!empty($ufAdd)) {
887 foreach ($ufAdd as $weightAdd => $ufGroupIdAdd) {
888
889 $ufJoinParamsAdd['weight'] = $weightAdd + $wtAdd;
890 $ufJoinParamsAdd['uf_group_id'] = $ufGroupIdAdd;
891
892 CRM_Core_BAO_UFJoin::create($ufJoinParamsAdd);
893 unset($ufJoinParamsAdd['id']);
894 }
895 }
896 }
897
03390e26 898 // get the profiles to evaluate what they collect
be2fb01f 899 $profileIds = [
03390e26 900 CRM_Utils_Array::value('custom_pre_id', $params),
901 CRM_Utils_Array::value('custom_post_id', $params),
be2fb01f
CW
902 ];
903 $additionalProfileIds = [
03390e26 904 CRM_Utils_Array::value('additional_custom_pre_id', $params),
905 CRM_Utils_Array::value('additional_custom_post_id', $params),
be2fb01f 906 ];
03390e26 907 // additional profile fields default to main if not set
908 if (!is_numeric($additionalProfileIds[0])) {
909 $additionalProfileIds[0] = $profileIds[0];
910 }
911 if (!is_numeric($additionalProfileIds[1])) {
912 $additionalProfileIds[1] = $profileIds[1];
913 }
914 //add multiple profiles if set
915 self::addMultipleProfiles($profileIds, $params, 'custom_post_id_multiple');
916 self::addMultipleProfiles($additionalProfileIds, $params, 'additional_custom_post_id_multiple');
917
0479b4c8 918 $cantDedupe = FALSE;
03390e26 919 $rgId = CRM_Utils_Array::value('dedupe_rule_group_id', $params, 0);
920
921 switch (self::canProfilesDedupe($profileIds, $rgId)) {
922 case 0:
923 $dedupeTitle = 'Duplicate Matching Impossible';
924 $cantDedupe = ts("The selected profiles do not contain the fields necessary to match registrations with existing contacts. This means all anonymous registrations will result in a new contact.");
925 break;
0479b4c8 926
03390e26 927 case 1:
928 $dedupeTitle = 'Duplicate Contacts Possible';
929 $cantDedupe = ts("The selected profiles can collect enough information to match registrations with existing contacts, but not all of the relevant fields are required. Anonymous registrations may result in duplicate contacts.");
930 }
931 if (!empty($params['is_multiple_registrations'])) {
22e263ad 932 switch (self::canProfilesDedupe($additionalProfileIds, $rgId)) {
03390e26 933 case 0:
934 $dedupeTitle = 'Duplicate Matching Impossible';
935 if ($cantDedupe) {
936 $cantDedupe = ts("The selected profiles do not contain the fields necessary to match registrations with existing contacts. This means all anonymous registrations will result in a new contact.");
937 }
938 else {
939 $cantDedupe = ts("The selected profiles do not contain the fields necessary to match additional participants with existing contacts. This means all additional participants will result in a new contact.");
940 }
941 break;
0479b4c8 942
03390e26 943 case 1:
944 if (!$cantDedupe) {
945 $dedupeTitle = 'Duplicate Contacts Possible';
946 $cantDedupe = ts("The selected profiles can collect enough information to match additional participants with existing contacts, but not all of the relevant fields are required. This may result in duplicate contacts.");
947 }
948 }
949 }
950 if ($cantDedupe) {
be2fb01f 951 CRM_Core_Session::setStatus($cantDedupe, $dedupeTitle, 'alert dedupenotify', ['expires' => 0]);
03390e26 952 }
953
5d92a7e7
CW
954 // Update tab "disabled" css class
955 $this->ajaxResponse['tabValid'] = !empty($params['is_online_registration']);
956
6a488035
TO
957 parent::endPostProcess();
958 }
6a488035
TO
959
960 /**
961 * Return a descriptive name for the page, used in wizard header
962 *
963 * @return string
6a488035
TO
964 */
965 public function getTitle() {
966 return ts('Online Registration');
967 }
96025800 968
6a488035 969}