Merge pull request #18464 from eileenmcnaughton/urlparamms
[civicrm-core.git] / CRM / Event / Form / Registration / Register.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_Registration_Register extends CRM_Event_Form_Registration {
21
22 /**
66f9e52b 23 * The fields involved in this page.
2dde9c7f 24 *
90b461f1 25 * @var array
6a488035
TO
26 */
27 public $_fields;
28
6a488035
TO
29 /**
30 * The status message that user view.
2dde9c7f 31 *
32 * @var string
6a488035 33 */
2dde9c7f 34 protected $_waitlistMsg;
35 protected $_requireApprovalMsg;
6a488035 36
3bdf1f3a 37 /**
38 * Deprecated parameter that we hope to remove.
39 *
40 * @var bool
41 */
2dde9c7f 42 public $_quickConfig;
6a488035
TO
43
44 /**
3bdf1f3a 45 * Skip duplicate check.
46 *
47 * This can be set using hook_civicrm_buildForm() to override the registration dupe check.
2dde9c7f 48 *
90b461f1 49 * @var bool
0e480632 50 * @see https://issues.civicrm.org/jira/browse/CRM-7604
6a488035
TO
51 */
52 public $_skipDupeRegistrationCheck = FALSE;
53
cc789d46 54 public $_paymentProcessorID;
6a488035 55
16d1c8e2 56 /**
3bdf1f3a 57 * Show fee block or not.
58 *
9f266042 59 * @var bool
16d1c8e2 60 */
61 public $_noFees;
62
0b36bfd7 63 /**
9f266042 64 * Fee Block.
65 *
66 * @var array
0b36bfd7
MWMC
67 */
68 public $_feeBlock;
69
cc789d46 70 /**
3bdf1f3a 71 * Array of payment related fields to potentially display on this form (generally credit card or debit card fields).
72 *
73 * This is rendered via billingBlock.tpl.
74 *
cc789d46
EM
75 * @var array
76 */
be2fb01f 77 public $_paymentFields = [];
cc789d46 78
22ef0f8e 79 /**
80 * Is this submission incurring no costs.
81 *
82 * @param array $fields
83 * @param \CRM_Event_Form_Registration_Register $form
84 *
85 * @return bool
86 */
87 protected static function isZeroAmount($fields, $form): bool {
88 $isZeroAmount = FALSE;
89 if (!empty($fields['priceSetId'])) {
de6c59ca 90 if (empty($fields['amount'])) {
22ef0f8e 91 $isZeroAmount = TRUE;
92 }
93 }
94 elseif (!empty($fields['amount']) &&
95 (isset($form->_values['discount'][$fields['amount']])
96 && CRM_Utils_Array::value('value', $form->_values['discount'][$fields['amount']]) == 0
97 )
98 ) {
99 $isZeroAmount = TRUE;
100 }
101 elseif (!empty($fields['amount']) &&
102 (isset($form->_values['fee'][$fields['amount']])
103 && CRM_Utils_Array::value('value', $form->_values['fee'][$fields['amount']]) == 0
104 )
105 ) {
106 $isZeroAmount = TRUE;
107 }
108 return $isZeroAmount;
109 }
110
7b64dc81 111 /**
112 * Get the contact id for the registration.
113 *
114 * @param array $fields
0b36bfd7 115 * @param CRM_Event_Form_Registration $form
7b64dc81 116 * @param bool $isAdditional
117 *
118 * @return int|null
119 */
0b36bfd7 120 public static function getRegistrationContactID($fields, $form, $isAdditional) {
7b64dc81 121 $contactID = NULL;
122 if (!$isAdditional) {
0b36bfd7 123 $contactID = $form->getContactID();
7b64dc81 124 }
125 if (!$contactID && is_array($fields) && $fields) {
b8cb7e46 126 $contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($fields, 'Individual', 'Unsupervised', [], FALSE, CRM_Utils_Array::value('dedupe_rule_group_id', $form->_values['event']), ['event_id' => CRM_Utils_Array::value('id', $form->_values['event'])]);
7b64dc81 127 }
128 return $contactID;
129 }
130
6a488035 131 /**
66f9e52b 132 * Set variables up before form is built.
2dde9c7f 133 *
134 * @throws \CRM_Core_Exception
6a488035 135 */
00be9182 136 public function preProcess() {
6a488035 137 parent::preProcess();
7bf9cde2 138
6a488035
TO
139 //CRM-4320.
140 //here we can't use parent $this->_allowWaitlist as user might
cc789d46 141 //walk back and we might set this value in this postProcess.
6a488035 142 //(we set when spaces < group count and want to allow become part of waiting )
6a488035
TO
143 $eventFull = CRM_Event_BAO_Participant::eventFull($this->_eventId, FALSE, CRM_Utils_Array::value('has_waitlist', $this->_values['event']));
144
b6a469c5
CW
145 // Get payment processors if appropriate for this event
146 // We hide the payment fields if the event is full or requires approval,
147 // and the current user has not yet been approved CRM-12279
16d1c8e2 148 $this->_noFees = (($eventFull || $this->_requireApproval) && !$this->_allowConfirmation);
be2fb01f 149 $this->_paymentProcessors = $this->_noFees ? [] : $this->get('paymentProcessors');
42e3a033 150 $this->preProcessPaymentOptions();
b6a469c5 151
6a488035 152 $this->_allowWaitlist = FALSE;
8cc574cf 153 if ($eventFull && !$this->_allowConfirmation && !empty($this->_values['event']['has_waitlist'])) {
6a488035 154 $this->_allowWaitlist = TRUE;
9c1bc317 155 $this->_waitlistMsg = $this->_values['event']['waitlist_text'] ?? NULL;
6a488035
TO
156 if (!$this->_waitlistMsg) {
157 $this->_waitlistMsg = ts('This event is currently full. However you can register now and get added to a waiting list. You will be notified if spaces become available.');
158 }
159 }
160 $this->set('allowWaitlist', $this->_allowWaitlist);
161
162 //To check if the user is already registered for the event(CRM-2426)
163 if (!$this->_skipDupeRegistrationCheck) {
164 self::checkRegistration(NULL, $this);
165 }
166
167 $this->assign('availableRegistrations', $this->_availableRegistrations);
168
169 // get the participant values from EventFees.php, CRM-4320
170 if ($this->_allowConfirmation) {
171 CRM_Event_Form_EventFees::preProcess($this);
172 }
6a488035
TO
173 }
174
175 /**
70d1766d 176 * Set default values for the form.
2dde9c7f 177 *
178 * @return array
179 *
180 * @throws \CRM_Core_Exception
181 * @throws \CiviCRM_API3_Exception
6a488035 182 */
00be9182 183 public function setDefaultValues() {
be2fb01f 184 $this->_defaults = [];
5ec4b965 185 if (!$this->_allowConfirmation && $this->_requireApproval) {
186 $this->_defaults['bypass_payment'] = 1;
187 }
5c280496 188 $contactID = $this->getContactID();
70d1766d 189 CRM_Core_Payment_Form::setDefaultValues($this, $contactID);
a28e436f 190
c7d52684 191 CRM_Event_BAO_Participant::formatFieldsAndSetProfileDefaults($contactID, $this);
3feb567a 192
13ac605f
DG
193 // Set default payment processor as default payment_processor radio button value
194 if (!empty($this->_paymentProcessors)) {
195 foreach ($this->_paymentProcessors as $pid => $value) {
a7488080 196 if (!empty($value['is_default'])) {
e02d7e96 197 $this->_defaults['payment_processor_id'] = $pid;
13ac605f
DG
198 }
199 }
200 }
201
6a488035
TO
202 //if event is monetary and pay later is enabled and payment
203 //processor is not available then freeze the pay later checkbox with
204 //default check
a7488080 205 if (!empty($this->_values['event']['is_pay_later']) &&
6a488035
TO
206 !is_array($this->_paymentProcessor)
207 ) {
208 $this->_defaults['is_pay_later'] = 1;
209 }
210
211 //set custom field defaults
212 if (!empty($this->_fields)) {
213 //load default campaign from page.
214 if (array_key_exists('participant_campaign_id', $this->_fields)) {
215 $this->_defaults['participant_campaign_id'] = CRM_Utils_Array::value('campaign_id',
216 $this->_values['event']
217 );
218 }
219
220 foreach ($this->_fields as $name => $field) {
221 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
222 // fix for CRM-1743
223 if (!isset($this->_defaults[$name])) {
224 CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, $name, $this->_defaults,
225 NULL, CRM_Profile_Form::MODE_REGISTER
226 );
227 }
228 }
229 }
230 }
231
232 //fix for CRM-3088, default value for discount set.
233 $discountId = NULL;
234 if (!empty($this->_values['discount'])) {
235 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
236 if ($discountId) {
237 if (isset($this->_values['event']['default_discount_fee_id'])) {
238 $discountKey = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue',
239 $this->_values['event']['default_discount_fee_id'],
240 'weight', 'id'
241 );
242
243 $this->_defaults['amount'] = key(array_slice($this->_values['discount'][$discountId],
353ffa53
TO
244 $discountKey - 1, $discountKey, TRUE
245 ));
6a488035
TO
246 }
247 }
248 }
249
250 // add this event's default participant role to defaults array
251 // (for cases where participant_role field is included in form via profile)
252 if ($this->_values['event']['default_role_id']) {
608e6658 253 $this->_defaults['participant_role']
254 = $this->_defaults['participant_role_id'] = $this->_values['event']['default_role_id'];
6a488035
TO
255 }
256 if ($this->_priceSetId && !empty($this->_feeBlock)) {
257 foreach ($this->_feeBlock as $key => $val) {
0dc0b759 258 if (empty($val['options'])) {
259 continue;
260 }
be2fb01f 261 $optionFullIds = CRM_Utils_Array::value('option_full_ids', $val, []);
6a488035 262 foreach ($val['options'] as $keys => $values) {
8cc574cf 263 if ($values['is_default'] && empty($values['is_full'])) {
6a488035
TO
264
265 if ($val['html_type'] == 'CheckBox') {
266 $this->_defaults["price_{$key}"][$keys] = 1;
267 }
268 else {
269 $this->_defaults["price_{$key}"] = $keys;
270 }
271 }
272 }
0dc0b759 273 $unsetSubmittedOptions[$val['id']] = $optionFullIds;
6a488035 274 }
0dc0b759 275 //reset values for all options those are full.
276 CRM_Event_Form_Registration::resetElementValue($unsetSubmittedOptions, $this);
6a488035
TO
277 }
278
279 //set default participant fields, CRM-4320.
280 $hasAdditionalParticipants = FALSE;
281 if ($this->_allowConfirmation) {
282 $this->_contactId = $contactID;
283 $this->_discountId = $discountId;
284 $forcePayLater = CRM_Utils_Array::value('is_pay_later', $this->_defaults, FALSE);
285 $this->_defaults = array_merge($this->_defaults, CRM_Event_Form_EventFees::setDefaultValues($this));
286 $this->_defaults['is_pay_later'] = $forcePayLater;
287
288 if ($this->_additionalParticipantIds) {
289 $hasAdditionalParticipants = TRUE;
290 $this->_defaults['additional_participants'] = count($this->_additionalParticipantIds);
291 }
292 }
293 $this->assign('hasAdditionalParticipants', $hasAdditionalParticipants);
294
295 // //hack to simplify credit card entry for testing
296 // $this->_defaults['credit_card_type'] = 'Visa';
297 // $this->_defaults['credit_card_number'] = '4807731747657838';
298 // $this->_defaults['cvv2'] = '000';
299 // $this->_defaults['credit_card_exp_date'] = array( 'Y' => '2010', 'M' => '05' );
300
301 // to process Custom data that are appended to URL
302 $getDefaults = CRM_Core_BAO_CustomGroup::extractGetParams($this, "'Contact', 'Individual', 'Contribution', 'Participant'");
303 if (!empty($getDefaults)) {
304 $this->_defaults = array_merge($this->_defaults, $getDefaults);
305 }
306
307 return $this->_defaults;
308 }
309
310 /**
66f9e52b 311 * Build the form object.
6a488035
TO
312 */
313 public function buildQuickForm() {
4839c695
KJ
314 // build profiles first so that we can determine address fields etc
315 // and then show copy address checkbox
316 $this->buildCustom($this->_values['custom_pre_id'], 'customPre');
317 $this->buildCustom($this->_values['custom_post_id'], 'customPost');
318
d38c288e 319 // CRM-18399: used by template to pass pre profile id as a url arg
320 $this->assign('custom_pre_id', $this->_values['custom_pre_id']);
4839c695 321
cc789d46 322 CRM_Core_Payment_ProcessorForm::buildQuickForm($this);
6a488035 323
5c280496 324 $contactID = $this->getContactID();
37326fa1
DG
325 if ($contactID) {
326 $this->assign('contact_id', $contactID);
f498a273 327 $this->assign('display_name', CRM_Contact_BAO_Contact::displayName($contactID));
37326fa1 328 }
6a488035 329
6a488035
TO
330 $bypassPayment = $allowGroupOnWaitlist = $isAdditionalParticipants = FALSE;
331 if ($this->_values['event']['is_multiple_registrations']) {
332 // don't allow to add additional during confirmation if not preregistered.
333 if (!$this->_allowConfirmation || $this->_additionalParticipantIds) {
f1bc01e0 334 // CRM-17745: Make maximum additional participants configurable
6a488035 335 // Label is value + 1, since the code sees this is ADDITIONAL participants (in addition to "self")
be2fb01f 336 $additionalOptions = [];
f1bc01e0 337 $additionalOptions[''] = 1;
30ddbdcb 338 for ($i = 1; $i <= $this->_values['event']['max_additional_participants']; $i++) {
f1bc01e0
J
339 $additionalOptions[$i] = $i + 1;
340 }
5f39c1a6 341 $this->add('select', 'additional_participants',
6a488035
TO
342 ts('How many people are you registering?'),
343 $additionalOptions,
344 NULL,
be2fb01f 345 ['onChange' => "allowParticipant()"]
6a488035
TO
346 );
347 $isAdditionalParticipants = TRUE;
348 }
349 }
350
5ec4b965 351 if (!$this->_allowConfirmation) {
352 $bypassPayment = TRUE;
353 }
354
6a488035 355 //hack to allow group to register w/ waiting
8cc574cf 356 if ((!empty($this->_values['event']['is_multiple_registrations']) ||
6a488035
TO
357 $this->_priceSetId
358 ) &&
359 !$this->_allowConfirmation &&
353ffa53
TO
360 is_numeric($this->_availableRegistrations) && !empty($this->_values['event']['has_waitlist'])
361 ) {
6a488035
TO
362 $bypassPayment = TRUE;
363 //case might be group become as a part of waitlist.
364 //If not waitlist then they require admin approve.
365 $allowGroupOnWaitlist = TRUE;
be2fb01f 366 $this->_waitlistMsg = ts("This event has only %1 space(s) left. If you continue and register more than %1 people (including yourself ), the whole group will be wait listed. Or, you can reduce the number of people you are registering to %1 to avoid being put on the waiting list.", [1 => $this->_availableRegistrations]);
6a488035
TO
367
368 if ($this->_requireApproval) {
369 $this->_requireApprovalMsg = CRM_Utils_Array::value('approval_req_text', $this->_values['event'],
370 ts('Registration for this event requires approval. Once your registration(s) have been reviewed, you will receive an email with a link to a web page where you can complete the registration process.')
371 );
372 }
373 }
374
375 //case where only approval needed - no waitlist.
376 if ($this->_requireApproval &&
377 !$this->_allowWaitlist && !$bypassPayment
378 ) {
379 $this->_requireApprovalMsg = CRM_Utils_Array::value('approval_req_text', $this->_values['event'],
380 ts('Registration for this event requires approval. Once your registration has been reviewed, you will receive an email with a link to a web page where you can complete the registration process.')
381 );
382 }
383
384 //lets display status to primary page only.
385 $this->assign('waitlistMsg', $this->_waitlistMsg);
386 $this->assign('requireApprovalMsg', $this->_requireApprovalMsg);
387 $this->assign('allowGroupOnWaitlist', $allowGroupOnWaitlist);
388 $this->assign('isAdditionalParticipants', $isAdditionalParticipants);
389
6a488035
TO
390 if ($this->_values['event']['is_monetary']) {
391 self::buildAmount($this);
392 }
393
2aaa619e 394 if ($contactID === 0 && !$this->_values['event']['is_multiple_registrations']) {
e1ce628e 395 //@todo we are blocking for multiple registrations because we haven't tested
f956cd24 396 $this->addCIDZeroOptions();
596bff78 397 }
6a488035
TO
398
399 if ($this->_values['event']['is_monetary']) {
1421b010 400 $this->addPaymentProcessorFieldsToForm();
6a488035
TO
401 }
402
be2fb01f 403 $this->addElement('hidden', 'bypass_payment', NULL, ['id' => 'bypass_payment']);
5ec4b965 404
6a488035 405 $this->assign('bypassPayment', $bypassPayment);
6a488035 406
2aaa619e 407 if (!$contactID) {
6a488035
TO
408 $createCMSUser = FALSE;
409
410 if ($this->_values['custom_pre_id']) {
411 $profileID = $this->_values['custom_pre_id'];
412 $createCMSUser = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'is_cms_user');
413 }
414
415 if (!$createCMSUser &&
416 $this->_values['custom_post_id']
417 ) {
418 if (!is_array($this->_values['custom_post_id'])) {
be2fb01f 419 $profileIDs = [$this->_values['custom_post_id']];
6a488035
TO
420 }
421 else {
422 $profileIDs = $this->_values['custom_post_id'];
423 }
424 foreach ($profileIDs as $pid) {
425 if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $pid, 'is_cms_user')) {
426 $profileID = $pid;
427 $createCMSUser = TRUE;
428 break;
429 }
430 }
431 }
432
433 if ($createCMSUser) {
434 CRM_Core_BAO_CMSUser::buildForm($this, $profileID, TRUE);
435 }
436 }
437
438 //we have to load confirm contribution button in template
439 //when multiple payment processor as the user
440 //can toggle with payment processor selection
441 $billingModePaymentProcessors = 0;
442 if (!CRM_Utils_System::isNull($this->_paymentProcessors)) {
443 foreach ($this->_paymentProcessors as $key => $values) {
444 if ($values['billing_mode'] == CRM_Core_Payment::BILLING_MODE_BUTTON) {
445 $billingModePaymentProcessors++;
446 }
447 }
448 }
449
450 if ($billingModePaymentProcessors && count($this->_paymentProcessors) == $billingModePaymentProcessors) {
451 $allAreBillingModeProcessors = TRUE;
0db6c3e1
TO
452 }
453 else {
6a488035
TO
454 $allAreBillingModeProcessors = FALSE;
455 }
456
8cc574cf 457 if (!$allAreBillingModeProcessors || !empty($this->_values['event']['is_pay_later']) || $bypassPayment
6a488035
TO
458 ) {
459
460 //freeze button to avoid multiple calls.
a7488080 461 if (empty($this->_values['event']['is_monetary'])) {
423616fa 462 $this->submitOnce = TRUE;
6a488035 463 }
2a6da8d7 464
1909126f 465 // CRM-11182 - Optional confirmation screen
466 // Change button label depending on whether the next action is confirm or register
1b9aa3aa
AH
467 $buttonParams = [
468 'type' => 'upload',
469 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
470 'isDefault' => TRUE,
471 ];
1909126f 472 if (
473 !$this->_values['event']['is_multiple_registrations']
d6121d3e 474 && !$this->_values['event']['is_monetary']
1909126f 475 && !$this->_values['event']['is_confirm_enabled']
476 ) {
1b9aa3aa 477 $buttonParams['name'] = ts('Register');
0db6c3e1
TO
478 }
479 else {
1b9aa3aa
AH
480 $buttonParams['name'] = ts('Review your registration');
481 $buttonParams['icon'] = 'fa-chevron-right';
1909126f 482 }
2a6da8d7 483
1b9aa3aa 484 $this->addButtons([$buttonParams]);
6a488035
TO
485 }
486
be2fb01f 487 $this->addFormRule(['CRM_Event_Form_Registration_Register', 'formRule'], $this);
86c0d461 488 $this->unsavedChangesWarn = TRUE;
6a488035
TO
489
490 // add pcp fields
491 if ($this->_pcpId) {
492 CRM_PCP_BAO_PCP::buildPcp($this->_pcpId, $this);
493 }
494 }
495
496 /**
100fef9d 497 * Build the radio/text form elements for the amount field
6a488035 498 *
0b36bfd7 499 * @param CRM_Event_Form_Registration_Register $form
d4dd1e85
TO
500 * Form object.
501 * @param bool $required
502 * True if you want to add formRule.
503 * @param int $discountId
504 * Discount id for the event.
2dde9c7f 505 *
506 * @throws \CRM_Core_Exception
6a488035 507 */
90b461f1 508 public static function buildAmount(&$form, $required = TRUE, $discountId = NULL) {
16d1c8e2 509 // build amount only when needed, skip incase of event full and waitlisting is enabled
510 // and few other conditions check preProcess()
a2a1e950 511 if (property_exists($form, '_noFees') && $form->_noFees) {
16d1c8e2 512 return;
513 }
514
6a488035 515 //if payment done, no need to build the fee block.
7bf9cde2 516 if (!empty($form->_paymentId)) {
b6e641a4 517 //fix to display line item in update mode.
2e1f50d6 518 $form->assign('priceSet', $form->_priceSet ?? NULL);
6a488035
TO
519 return;
520 }
521
9c1bc317 522 $feeFields = $form->_values['fee'] ?? NULL;
6a488035
TO
523
524 if (is_array($feeFields)) {
525 $form->_feeBlock = &$form->_values['fee'];
526 }
527
528 //check for discount.
9c1bc317 529 $discountedFee = $form->_values['discount'] ?? NULL;
6a488035
TO
530 if (is_array($discountedFee) && !empty($discountedFee)) {
531 if (!$discountId) {
532 $form->_discountId = $discountId = CRM_Core_BAO_Discount::findSet($form->_eventId, 'civicrm_event');
533 }
534 if ($discountId) {
535 $form->_feeBlock = &$form->_values['discount'][$discountId];
536 }
537 }
538 if (!is_array($form->_feeBlock)) {
be2fb01f 539 $form->_feeBlock = [];
6a488035
TO
540 }
541
542 //its time to call the hook.
543 CRM_Utils_Hook::buildAmount('event', $form, $form->_feeBlock);
544
545 //reset required if participant is skipped.
546 $button = substr($form->controller->getButtonName(), -4);
547 if ($required && $button == 'skip') {
548 $required = FALSE;
549 }
550
551 $className = CRM_Utils_System::getClassName($form);
552
553 //build the priceset fields.
554 if (isset($form->_priceSetId) && $form->_priceSetId) {
555
556 //format price set fields across option full.
557 self::formatFieldsForOptionFull($form);
558
a7488080 559 if (!empty($form->_priceSet['is_quick_config'])) {
6a488035
TO
560 $form->_quickConfig = $form->_priceSet['is_quick_config'];
561 }
562 $form->add('hidden', 'priceSetId', $form->_priceSetId);
563
c7b3d063 564 // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
ab8a593e 565 $adminFieldVisible = FALSE;
755a1835 566 if (CRM_Core_Permission::check('administer CiviCRM data')) {
4eeb9a5b 567 $adminFieldVisible = TRUE;
c7b3d063
DG
568 }
569
a13c171d
CR
570 $hideAdminValues = TRUE;
571 if (CRM_Core_Permission::check('edit event participants')) {
572 $hideAdminValues = FALSE;
573 }
574
6a488035 575 foreach ($form->_feeBlock as $field) {
d06f3157 576 // public AND admin visibility fields are included for back-office registration and back-office change selections
6a488035 577 if (CRM_Utils_Array::value('visibility', $field) == 'public' ||
4eeb9a5b 578 (CRM_Utils_Array::value('visibility', $field) == 'admin' && $adminFieldVisible == TRUE) ||
d06f3157 579 $className == 'CRM_Event_Form_Participant' ||
8535cf1c 580 $className === 'CRM_Event_Form_Task_Register' ||
d06f3157 581 $className == 'CRM_Event_Form_ParticipantFeeSelection'
6a488035
TO
582 ) {
583 $fieldId = $field['id'];
584 $elementName = 'price_' . $fieldId;
585
9c1bc317 586 $isRequire = $field['is_required'] ?? NULL;
6a488035
TO
587 if ($button == 'skip') {
588 $isRequire = FALSE;
589 }
590
591 //user might modified w/ hook.
9c1bc317 592 $options = $field['options'] ?? NULL;
8535cf1c 593 $formClasses = ['CRM_Event_Form_Participant', 'CRM_Event_Form_Task_Register', 'CRM_Event_Form_ParticipantFeeSelection'];
a13c171d 594
6a488035
TO
595 if (!is_array($options)) {
596 continue;
597 }
a13c171d 598 elseif ($hideAdminValues && !in_array($className, $formClasses)) {
ad2785a2
CR
599 $publicVisibilityID = CRM_Price_BAO_PriceField::getVisibilityOptionID('public');
600 $adminVisibilityID = CRM_Price_BAO_PriceField::getVisibilityOptionID('admin');
601
a13c171d 602 foreach ($options as $key => $currentOption) {
ad2785a2
CR
603 $optionVisibility = CRM_Utils_Array::value('visibility_id', $currentOption, $publicVisibilityID);
604 if ($optionVisibility == $adminVisibilityID) {
a13c171d
CR
605 unset($options[$key]);
606 }
607 }
608 }
6a488035 609
be2fb01f 610 $optionFullIds = CRM_Utils_Array::value('option_full_ids', $field, []);
6a488035
TO
611
612 //soft suppress required rule when option is full.
613 if (!empty($optionFullIds) && (count($options) == count($optionFullIds))) {
614 $isRequire = FALSE;
615 }
1019b2fe
SL
616 if (!empty($options)) {
617 //build the element.
618 CRM_Price_BAO_PriceField::addQuickFormElement($form,
619 $elementName,
620 $fieldId,
621 FALSE,
622 $isRequire,
623 NULL,
624 $options,
625 $optionFullIds
626 );
627 }
6a488035
TO
628 }
629 }
a7f41fd0 630 $form->_priceSet['id'] = $form->_priceSet['id'] ?? $form->_priceSetId;
6a488035
TO
631 $form->assign('priceSet', $form->_priceSet);
632 }
633 else {
be2fb01f 634 $eventFeeBlockValues = [];
6a488035
TO
635 foreach ($form->_feeBlock as $fee) {
636 if (is_array($fee)) {
637
638 //CRM-7632, CRM-6201
639 $totalAmountJs = NULL;
8535cf1c 640 if ($className == 'CRM_Event_Form_Participant' || $className === 'CRM_Event_Form_Task_Register') {
be2fb01f 641 $totalAmountJs = ['onClick' => "fillTotalAmount(" . $fee['value'] . ")"];
6a488035
TO
642 }
643
644 $eventFeeBlockValues['amount_id_' . $fee['amount_id']] = $fee['value'];
645 $elements[] = &$form->createElement('radio', NULL, '',
646 CRM_Utils_Money::format($fee['value']) . ' ' .
647 $fee['label'],
648 $fee['amount_id'],
649 $totalAmountJs
650 );
651 }
652 }
653 $form->assign('eventFeeBlockValues', json_encode($eventFeeBlockValues));
654
9c1bc317 655 $form->_defaults['amount'] = $form->_values['event']['default_fee_id'] ?? NULL;
6a488035
TO
656 $element = &$form->addGroup($elements, 'amount', ts('Event Fee(s)'), '<br />');
657 if (isset($form->_online) && $form->_online) {
658 $element->freeze();
659 }
660 if ($required) {
661 $form->addRule('amount', ts('Fee Level is a required field.'), 'required');
662 }
663 }
664 }
665
0cf587a7 666 /**
0b36bfd7 667 * @param CRM_Event_Form_Registration $form
0cf587a7 668 */
6a488035
TO
669 public static function formatFieldsForOptionFull(&$form) {
670 $priceSet = $form->get('priceSet');
671 $priceSetId = $form->get('priceSetId');
be2fb01f 672 $defaultPricefieldIds = [];
e9bb507e 673 if (!empty($form->_values['line_items'])) {
674 foreach ($form->_values['line_items'] as $lineItem) {
675 $defaultPricefieldIds[] = $lineItem['price_field_value_id'];
676 }
677 }
6a488035
TO
678 if (!$priceSetId ||
679 !is_array($priceSet) ||
353ffa53
TO
680 empty($priceSet) || empty($priceSet['optionsMaxValueTotal'])
681 ) {
6a488035
TO
682 return;
683 }
684
be2fb01f 685 $skipParticipants = $formattedPriceSetDefaults = [];
e03317f1 686 if (!empty($form->_allowConfirmation) && (isset($form->_pId) || isset($form->_additionalParticipantId))) {
2e1f50d6 687 $participantId = $form->_pId ?? $form->_additionalParticipantId;
6a488035
TO
688 $pricesetDefaults = CRM_Event_Form_EventFees::setDefaultPriceSet($participantId,
689 $form->_eventId
690 );
691 // modify options full to respect the selected fields
692 // options on confirmation.
217d80ab 693 $formattedPriceSetDefaults = self::formatPriceSetParams($form, $pricesetDefaults);
6a488035
TO
694
695 // to skip current registered participants fields option count on confirmation.
696 $skipParticipants[] = $form->_participantId;
697 if (!empty($form->_additionalParticipantIds)) {
698 $skipParticipants = array_merge($skipParticipants, $form->_additionalParticipantIds);
699 }
700 }
701
702 $className = CRM_Utils_System::getClassName($form);
703
704 //get the current price event price set options count.
705 $currentOptionsCount = self::getPriceSetOptionCount($form);
706 $recordedOptionsCount = CRM_Event_BAO_Participant::priceSetOptionsCount($form->_eventId, $skipParticipants);
e9bb507e 707 $optionFullTotalAmount = 0;
0dc0b759 708 $currentParticipantNo = (int) substr($form->_name, 12);
6a488035 709 foreach ($form->_feeBlock as & $field) {
be2fb01f 710 $optionFullIds = [];
6a488035
TO
711 $fieldId = $field['id'];
712 if (!is_array($field['options'])) {
713 continue;
714 }
715 foreach ($field['options'] as & $option) {
353ffa53
TO
716 $optId = $option['id'];
717 $count = CRM_Utils_Array::value('count', $option, 0);
718 $maxValue = CRM_Utils_Array::value('max_value', $option, 0);
719 $dbTotalCount = CRM_Utils_Array::value($optId, $recordedOptionsCount, 0);
6a488035
TO
720 $currentTotalCount = CRM_Utils_Array::value($optId, $currentOptionsCount, 0);
721
79b152ac 722 $totalCount = $currentTotalCount + $dbTotalCount;
6a488035
TO
723 $isFull = FALSE;
724 if ($maxValue &&
0dc0b759 725 (($totalCount >= $maxValue) &&
726 (empty($form->_lineItem[$currentParticipantNo][$optId]['price_field_id']) || $dbTotalCount >= $maxValue))
6a488035
TO
727 ) {
728 $isFull = TRUE;
729 $optionFullIds[$optId] = $optId;
e9bb507e 730 if ($field['html_type'] != 'Select') {
731 if (in_array($optId, $defaultPricefieldIds)) {
732 $optionFullTotalAmount += CRM_Utils_Array::value('amount', $option);
733 }
734 }
735 else {
736 if (!empty($defaultPricefieldIds) && in_array($optId, $defaultPricefieldIds)) {
737 unset($optionFullIds[$optId]);
738 }
739 }
6a488035 740 }
6a488035
TO
741 //here option is not full,
742 //but we don't want to allow participant to increase
743 //seats at the time of re-walking registration.
744 if ($count &&
8dfe9fe3 745 !empty($form->_allowConfirmation) &&
6a488035
TO
746 !empty($formattedPriceSetDefaults)
747 ) {
217d80ab 748 if (empty($formattedPriceSetDefaults["price_{$field}"]) || empty($formattedPriceSetDefaults["price_{$fieldId}"][$optId])) {
6a488035
TO
749 $optionFullIds[$optId] = $optId;
750 $isFull = TRUE;
751 }
752 }
753 $option['is_full'] = $isFull;
754 $option['db_total_count'] = $dbTotalCount;
755 $option['total_option_count'] = $dbTotalCount + $currentTotalCount;
756 }
757
758 //ignore option full for offline registration.
8535cf1c 759 if ($className == 'CRM_Event_Form_Participant' || $className === 'CRM_Event_Form_Task_Register') {
be2fb01f 760 $optionFullIds = [];
6a488035
TO
761 }
762
763 //finally get option ids in.
764 $field['option_full_ids'] = $optionFullIds;
765 }
e9bb507e 766 $form->assign('optionFullTotalAmount', $optionFullTotalAmount);
6a488035
TO
767 }
768
769 /**
66f9e52b 770 * Global form rule.
6a488035 771 *
d4dd1e85
TO
772 * @param array $fields
773 * The input form values.
774 * @param array $files
775 * The uploaded files if any.
22ef0f8e 776 * @param \CRM_Event_Form_Registration_Register $form
2a6da8d7 777 *
72b3a70c
CW
778 * @return bool|array
779 * true if no errors, else array of errors
2dde9c7f 780 *
781 * @throws \CRM_Core_Exception
6a488035 782 */
0b36bfd7 783 public static function formRule($fields, $files, $form) {
be2fb01f 784 $errors = [];
6a488035 785 //check that either an email or firstname+lastname is included in the form(CRM-9587)
0b36bfd7 786 self::checkProfileComplete($fields, $errors, $form->_eventId);
6a488035 787 //To check if the user is already registered for the event(CRM-2426)
0b36bfd7
MWMC
788 if (!$form->_skipDupeRegistrationCheck) {
789 self::checkRegistration($fields, $form);
6a488035
TO
790 }
791 //check for availability of registrations.
0b36bfd7
MWMC
792 if (!$form->_allowConfirmation && empty($fields['bypass_payment']) &&
793 is_numeric($form->_availableRegistrations) &&
794 CRM_Utils_Array::value('additional_participants', $fields) >= $form->_availableRegistrations
6a488035 795 ) {
be2fb01f 796 $errors['additional_participants'] = ts("There is only enough space left on this event for %1 participant(s).", [1 => $form->_availableRegistrations]);
6a488035
TO
797 }
798
89d51753 799 $numberAdditionalParticipants = $fields['additional_participants'] ?? 0;
800
801 if ($numberAdditionalParticipants && !CRM_Utils_Rule::positiveInteger($fields['additional_participants'])) {
802 $errors['additional_participants'] = ts('Please enter a whole number for Number of additional people.');
803 }
804
6a488035 805 // during confirmation don't allow to increase additional participants, CRM-4320
89d51753 806 if ($form->_allowConfirmation && $numberAdditionalParticipants &&
0b36bfd7 807 is_array($form->_additionalParticipantIds) &&
89d51753 808 $numberAdditionalParticipants > count($form->_additionalParticipantIds)
6a488035 809 ) {
be2fb01f 810 $errors['additional_participants'] = ts("Oops. It looks like you are trying to increase the number of additional people you are registering for. You can confirm registration for a maximum of %1 additional people.", [1 => count($form->_additionalParticipantIds)]);
6a488035
TO
811 }
812
813 //don't allow to register w/ waiting if enough spaces available.
0b36bfd7
MWMC
814 if (!empty($fields['bypass_payment']) && $form->_allowConfirmation) {
815 if (!is_numeric($form->_availableRegistrations) ||
816 (empty($fields['priceSetId']) && CRM_Utils_Array::value('additional_participants', $fields) < $form->_availableRegistrations)
6a488035
TO
817 ) {
818 $errors['bypass_payment'] = ts("Oops. There are enough available spaces in this event. You can not add yourself to the waiting list.");
819 }
820 }
821
6a488035 822 // priceset validations
0dc0b759 823 if (!empty($fields['priceSetId']) &&
0b36bfd7 824 !$form->_requireApproval && !$form->_allowWaitlist
0dc0b759 825 ) {
6a488035 826 //format params.
0b36bfd7 827 $formatted = self::formatPriceSetParams($form, $fields);
be2fb01f 828 $ppParams = [$formatted];
0b36bfd7
MWMC
829 $priceSetErrors = self::validatePriceSet($form, $ppParams);
830 $primaryParticipantCount = self::getParticipantCount($form, $ppParams);
6a488035
TO
831
832 //get price set fields errors in.
be2fb01f 833 $errors = array_merge($errors, CRM_Utils_Array::value(0, $priceSetErrors, []));
6a488035
TO
834
835 $totalParticipants = $primaryParticipantCount;
89d51753 836 if ($numberAdditionalParticipants) {
837 $totalParticipants += $numberAdditionalParticipants;
6a488035
TO
838 }
839
a7488080 840 if (empty($fields['bypass_payment']) &&
0b36bfd7
MWMC
841 !$form->_allowConfirmation &&
842 is_numeric($form->_availableRegistrations) &&
843 $form->_availableRegistrations < $totalParticipants
6a488035 844 ) {
be2fb01f 845 $errors['_qf_default'] = ts("Only %1 Registrations available.", [1 => $form->_availableRegistrations]);
6a488035
TO
846 }
847
be2fb01f 848 $lineItem = [];
0b36bfd7 849 CRM_Price_BAO_PriceSet::processAmount($form->_values['fee'], $fields, $lineItem);
601c7a24 850
851 $minAmt = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $fields['priceSetId'], 'min_amount');
6a488035
TO
852 if ($fields['amount'] < 0) {
853 $errors['_qf_default'] = ts('Event Fee(s) can not be less than zero. Please select the options accordingly');
854 }
601c7a24 855 elseif (!empty($minAmt) && $fields['amount'] < $minAmt) {
be2fb01f 856 $errors['_qf_default'] = ts('A minimum amount of %1 should be selected from Event Fee(s).', [
601c7a24 857 1 => CRM_Utils_Money::format($minAmt),
be2fb01f 858 ]);
601c7a24 859 }
6a488035 860 }
f2077611 861 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
862 if ($greetingType = CRM_Utils_Array::value($greeting, $fields)) {
863 $customizedValue = CRM_Core_PseudoConstant::getKey('CRM_Contact_BAO_Contact', $greeting . '_id', 'Customized');
864 if ($customizedValue == $greetingType && empty($fields[$greeting . '_custom'])) {
865 $errors[$greeting . '_custom'] = ts('Custom %1 is a required field if %1 is of type Customized.',
866 [1 => ucwords(str_replace('_', ' ', $greeting))]
867 );
868 }
869 }
870 }
6a488035 871
f48e6cf7 872 // @todo - can we remove the 'is_monetary' concept?
0b36bfd7
MWMC
873 if ($form->_values['event']['is_monetary']) {
874 if (empty($form->_requireApproval) && !empty($fields['amount']) && $fields['amount'] > 0 &&
1019b2fe 875 !isset($fields['payment_processor_id'])) {
e02d7e96 876 $errors['payment_processor_id'] = ts('Please select a Payment Method');
0d588131 877 }
6a488035 878
22ef0f8e 879 if (self::isZeroAmount($fields, $form)) {
880 return empty($errors) ? TRUE : $errors;
6a488035
TO
881 }
882
f48e6cf7 883 // also return if zero fees for valid members
884 if (!empty($fields['bypass_payment']) ||
0b36bfd7 885 (!$form->_allowConfirmation && ($form->_requireApproval || $form->_allowWaitlist))
6a488035
TO
886 ) {
887 return empty($errors) ? TRUE : $errors;
888 }
f48e6cf7 889 CRM_Core_Payment_Form::validatePaymentInstrument(
890 $fields['payment_processor_id'],
891 $fields,
892 $errors,
0b36bfd7 893 (!$form->_isBillingAddressRequiredForPayLater ? NULL : 'billing')
f48e6cf7 894 );
6a488035 895 }
6a488035 896
6a488035
TO
897 return empty($errors) ? TRUE : $errors;
898 }
899
900 /**
ec022878 901 * Check if profiles are complete when event registration occurs(CRM-9587).
902 *
903 * @param array $fields
904 * @param array $errors
905 * @param int $eventId
6a488035 906 */
00be9182 907 public static function checkProfileComplete($fields, &$errors, $eventId) {
6a488035
TO
908 $email = '';
909 foreach ($fields as $fieldname => $fieldvalue) {
910 if (substr($fieldname, 0, 6) == 'email-' && $fieldvalue) {
911 $email = $fieldvalue;
912 }
913 }
914
8cc574cf 915 if (!$email && !(!empty($fields['first_name']) && !empty($fields['last_name']))) {
be2fb01f 916 $defaults = $params = ['id' => $eventId];
6a488035
TO
917 CRM_Event_BAO_Event::retrieve($params, $defaults);
918 $message = ts("Mandatory fields (first name and last name, OR email address) are missing from this form.");
919 $errors['_qf_default'] = $message;
920 }
921 }
922
923 /**
66f9e52b 924 * Process the form submission.
6a488035
TO
925 */
926 public function postProcess() {
927 // get the submitted form values.
928 $params = $this->controller->exportValues($this->_name);
929
930 //set as Primary participant
931 $params['is_primary'] = 1;
932
8ae4d0d3 933 if ($this->_values['event']['is_pay_later']
e02d7e96 934 && (!array_key_exists('hidden_processor', $params) || $params['payment_processor_id'] == 0)
353ffa53 935 ) {
6a488035
TO
936 $params['is_pay_later'] = 1;
937 }
938 else {
939 $params['is_pay_later'] = 0;
940 }
941
942 $this->set('is_pay_later', $params['is_pay_later']);
943
944 // assign pay later stuff
945 $this->_params['is_pay_later'] = CRM_Utils_Array::value('is_pay_later', $params, FALSE);
946 $this->assign('is_pay_later', $params['is_pay_later']);
947 if ($params['is_pay_later']) {
948 $this->assign('pay_later_text', $this->_values['event']['pay_later_text']);
949 $this->assign('pay_later_receipt', $this->_values['event']['pay_later_receipt']);
950 }
6a488035 951
168e792f
DL
952 if (!$this->_allowConfirmation) {
953 // check if the participant is already registered
954 if (!$this->_skipDupeRegistrationCheck) {
7dfe13ab 955 $params['contact_id'] = self::getRegistrationContactID($params, $this, FALSE);
168e792f
DL
956 }
957 }
958
a7488080 959 if (!empty($params['image_URL'])) {
6a488035
TO
960 CRM_Contact_BAO_Contact::processImageParams($params);
961 }
962
963 //carry campaign to partcipants.
964 if (array_key_exists('participant_campaign_id', $params)) {
965 $params['campaign_id'] = $params['participant_campaign_id'];
966 }
967 else {
9c1bc317 968 $params['campaign_id'] = $this->_values['event']['campaign_id'] ?? NULL;
6a488035
TO
969 }
970
971 //hack to allow group to register w/ waiting
972 $primaryParticipantCount = self::getParticipantCount($this, $params);
973
974 $totalParticipants = $primaryParticipantCount;
a7488080 975 if (!empty($params['additional_participants'])) {
6a488035
TO
976 $totalParticipants += $params['additional_participants'];
977 }
8cc574cf 978 if (!$this->_allowConfirmation && !empty($params['bypass_payment']) &&
6a488035
TO
979 is_numeric($this->_availableRegistrations) &&
980 $totalParticipants > $this->_availableRegistrations
981 ) {
982 $this->_allowWaitlist = TRUE;
983 $this->set('allowWaitlist', TRUE);
984 }
985
986 //carry participant id if pre-registered.
987 if ($this->_allowConfirmation && $this->_participantId) {
988 $params['participant_id'] = $this->_participantId;
989 }
990
991 $params['defaultRole'] = 1;
992 if (array_key_exists('participant_role', $params)) {
993 $params['participant_role_id'] = $params['participant_role'];
994 }
995
996 if (array_key_exists('participant_role_id', $params)) {
997 $params['defaultRole'] = 0;
998 }
a7488080 999 if (empty($params['participant_role_id']) &&
6a488035
TO
1000 $this->_values['event']['default_role_id']
1001 ) {
1002 $params['participant_role_id'] = $this->_values['event']['default_role_id'];
1003 }
1004
1005 $config = CRM_Core_Config::singleton();
1006 $params['currencyID'] = $config->defaultCurrency;
1007
1008 if ($this->_values['event']['is_monetary']) {
1009 // we first reset the confirm page so it accepts new values
1010 $this->controller->resetPage('Confirm');
1011
1012 //added for discount
1013 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
c039f658 1014 $params['amount_level'] = $this->getAmountLevel($params, $discountId);
6a488035
TO
1015 if (!empty($this->_values['discount'][$discountId])) {
1016 $params['discount_id'] = $discountId;
6a488035
TO
1017 $params['amount'] = $this->_values['discount'][$discountId][$params['amount']]['value'];
1018 }
1019 elseif (empty($params['priceSetId'])) {
16d1c8e2 1020 if (!empty($params['amount'])) {
16d1c8e2 1021 $params['amount'] = $this->_values['fee'][$params['amount']]['value'];
1022 }
1023 else {
c039f658 1024 $params['amount'] = '';
16d1c8e2 1025 }
6a488035
TO
1026 }
1027 else {
be2fb01f 1028 $lineItem = [];
9da8dc8c 1029 CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem);
d91b8b33 1030 if ($params['tax_amount']) {
1031 $this->set('tax_amount', $params['tax_amount']);
1032 }
9d8d8fd0 1033 $submittedLineItems = $this->get('lineItem');
1034 if (!empty($submittedLineItems) && is_array($submittedLineItems)) {
0dc0b759 1035 $submittedLineItems[0] = $lineItem;
1036 }
1037 else {
be2fb01f 1038 $submittedLineItems = [$lineItem];
0dc0b759 1039 }
dba6436f 1040 $submittedLineItems = array_filter($submittedLineItems);
0dc0b759 1041 $this->set('lineItem', $submittedLineItems);
be2fb01f 1042 $this->set('lineItemParticipantsCount', [$primaryParticipantCount]);
6a488035
TO
1043 }
1044
1045 $this->set('amount', $params['amount']);
1046 $this->set('amount_level', $params['amount_level']);
1047
1048 // generate and set an invoiceID for this transaction
1049 $invoiceID = md5(uniqid(rand(), TRUE));
1050 $this->set('invoiceID', $invoiceID);
1051
b0c462ac 1052 if ($this->_paymentProcessor) {
077017db 1053 $payment = $this->_paymentProcessor['object'];
ec022878 1054 $payment->setBaseReturnUrl('civicrm/event/register');
6a488035 1055 }
0eb1f7ff 1056
1057 // ContributeMode is a deprecated concept. It is short-hand for a bunch of
1058 // assumptions we are working to remove.
6a488035
TO
1059 $this->set('contributeMode', 'direct');
1060
6a488035 1061 if ($this->_values['event']['is_monetary']) {
6a488035 1062 $params['currencyID'] = $config->defaultCurrency;
6a488035
TO
1063 $params['invoiceID'] = $invoiceID;
1064 }
d0ebccea 1065 $this->_params = $this->get('params');
ec022878 1066 // Set the button so we know what
1067 $params['button'] = $this->controller->getButtonName();
d0ebccea 1068 if (!empty($this->_params) && is_array($this->_params)) {
0dc0b759 1069 $this->_params[0] = $params;
1070 }
1071 else {
be2fb01f 1072 $this->_params = [];
0dc0b759 1073 $this->_params[] = $params;
1074 }
6a488035 1075 $this->set('params', $this->_params);
f92fc7eb 1076 if ($this->_paymentProcessor &&
223190c8 1077 // Actually we don't really need to check if it supports pre-approval - we could just call
1078 // it regardless as the function we call re-acts tot the rests of the preApproval call.
ec022878 1079 $this->_paymentProcessor['object']->supports('preApproval')
1080 && !$this->_allowWaitlist &&
1081 !$this->_requireApproval
f92fc7eb 1082 ) {
6a488035 1083
0f2b049e 1084 // The concept of contributeMode is deprecated - but still needs removal from the message templates.
ec022878 1085 $this->set('contributeMode', 'express');
6a488035 1086
ec022878 1087 // Send Event Name & Id in Params
1088 $params['eventName'] = $this->_values['event']['title'];
1089 $params['eventId'] = $this->_values['event']['id'];
6a488035 1090
ec022878 1091 $params['cancelURL'] = CRM_Utils_System::url('civicrm/event/register',
1092 "_qf_Register_display=1&qfKey={$this->controller->_key}",
1093 TRUE, NULL, FALSE
1094 );
de6c59ca 1095 if (!empty($params['additional_participants'])) {
ec022878 1096 $urlArgs = "_qf_Participant_1_display=1&rfp=1&qfKey={$this->controller->_key}";
1097 }
1098 else {
1099 $urlArgs = "_qf_Confirm_display=1&rfp=1&qfKey={$this->controller->_key}";
1100 }
1101 $params['returnURL'] = CRM_Utils_System::url('civicrm/event/register',
1102 $urlArgs,
1103 TRUE, NULL, FALSE
1104 );
1105 $params['invoiceID'] = $invoiceID;
6a488035 1106
ec022878 1107 $params['component'] = 'event';
1a093d07 1108 // This code is duplicated multiple places and should be consolidated.
1109 $params = $this->prepareParamsForPaymentProcessor($params);
223190c8 1110 $this->handlePreApproval($params);
6a488035 1111 }
f92fc7eb 1112 elseif ($this->_paymentProcessor &&
5e3148f4 1113 (int) $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY
f92fc7eb 1114 ) {
0f2b049e 1115 // The concept of contributeMode is deprecated - but still needs removal from the message templates.
6a488035
TO
1116 $this->set('contributeMode', 'notify');
1117 }
13f230bc 1118 }
1119 else {
1120 $params['description'] = ts('Online Event Registration') . ' ' . $this->_values['event']['title'];
6a488035 1121
be2fb01f 1122 $this->_params = [];
13f230bc 1123 $this->_params[] = $params;
1124 $this->set('params', $this->_params);
6a488035 1125
13f230bc 1126 if (
1127 empty($params['additional_participants'])
90b461f1
SL
1128 // CRM-11182 - Optional confirmation screen
1129 && !$this->_values['event']['is_confirm_enabled']
13f230bc 1130 ) {
3033e657 1131 $this->processRegistration($this->_params);
6a488035
TO
1132 }
1133 }
1134
1135 // If registering > 1 participant, give status message
de6c59ca 1136 if (!empty($params['additional_participants'])) {
6a488035
TO
1137 $statusMsg = ts('Registration information for participant 1 has been saved.');
1138 CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success');
1139 }
1140 }
6a488035 1141
6a488035 1142 /**
66f9e52b 1143 * Method to check if the user is already registered for the event.
6a488035
TO
1144 * and if result found redirect to the event info page
1145 *
d4dd1e85
TO
1146 * @param array $fields
1147 * The input form values(anonymous user).
0b36bfd7 1148 * @param CRM_Event_Form_Registration_Register $form
d4dd1e85
TO
1149 * Event data.
1150 * @param bool $isAdditional
1151 * Treat isAdditional participants a bit differently.
6a488035 1152 *
54957108 1153 * @return int
6a488035 1154 */
0b36bfd7 1155 public static function checkRegistration($fields, $form, $isAdditional = FALSE) {
6a488035
TO
1156 // CRM-3907, skip check for preview registrations
1157 // CRM-4320 participant need to walk wizard
7dfe13ab 1158 if (
6a2b3da2 1159 ($form->getPaymentMode() === 'test' || $form->_allowConfirmation)
6a488035
TO
1160 ) {
1161 return FALSE;
1162 }
1163
0b36bfd7 1164 $contactID = self::getRegistrationContactID($fields, $form, $isAdditional);
6a488035 1165
6a488035
TO
1166 if ($contactID) {
1167 $participant = new CRM_Event_BAO_Participant();
1168 $participant->contact_id = $contactID;
0b36bfd7 1169 $participant->event_id = $form->_values['event']['id'];
6a488035
TO
1170 if (!empty($fields['participant_role']) && is_numeric($fields['participant_role'])) {
1171 $participant->role_id = $fields['participant_role'];
1172 }
1173 else {
0b36bfd7 1174 $participant->role_id = $form->_values['event']['default_role_id'];
6a488035
TO
1175 }
1176 $participant->is_test = 0;
1177 $participant->find();
ed66ac46
JG
1178 // Event#30 - Anyone whose status type has `is_counted` OR is on the waitlist should be considered as registered.
1179 $statusTypes = CRM_Event_PseudoConstant::participantStatus(NULL, 'is_counted = 1') + CRM_Event_PseudoConstant::participantStatus(NULL, "name = 'On waitlist'");
6a488035
TO
1180 while ($participant->fetch()) {
1181 if (array_key_exists($participant->status_id, $statusTypes)) {
0b36bfd7 1182 if (!$isAdditional && !$form->_values['event']['allow_same_participant_emails']) {
6a488035 1183 $registerUrl = CRM_Utils_System::url('civicrm/event/register',
0b36bfd7 1184 "reset=1&id={$form->_values['event']['id']}&cid=0"
6a488035 1185 );
0b36bfd7
MWMC
1186 if ($form->_pcpId) {
1187 $registerUrl .= '&pcpId=' . $form->_pcpId;
6a488035 1188 }
ed66ac46
JG
1189 $registrationType = (CRM_Event_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'participant_status_id', 'On waitlist') == $participant->status_id) ? 'waitlisted' : 'registered';
1190 $status = ts("It looks like you are already %1 for this event. If you want to change your registration, or you feel that you've received this message in error, please contact the site administrator.", [1 => $registrationType]);
1191 $status .= ' ' . ts('You can also <a href="%1">register another participant</a>.', [1 => $registerUrl]);
7dfe13ab 1192 CRM_Core_Session::singleton()->setStatus($status, ts('Oops.'), 'alert');
6a488035 1193 $url = CRM_Utils_System::url('civicrm/event/info',
0b36bfd7 1194 "reset=1&id={$form->_values['event']['id']}&noFullMsg=true"
6a488035 1195 );
0b36bfd7 1196 if ($form->_action & CRM_Core_Action::PREVIEW) {
6a488035
TO
1197 $url .= '&action=preview';
1198 }
1199
0b36bfd7
MWMC
1200 if ($form->_pcpId) {
1201 $url .= '&pcpId=' . $form->_pcpId;
6a488035
TO
1202 }
1203
1204 CRM_Utils_System::redirect($url);
1205 }
1206
1207 if ($isAdditional) {
06141953 1208 $status = ts("It looks like this participant is already registered for this event. If you want to change your registration, or you feel that you've received this message in error, please contact the site administrator.");
7dfe13ab 1209 CRM_Core_Session::singleton()->setStatus($status, ts('Oops.'), 'alert');
6a488035
TO
1210 return $participant->id;
1211 }
1212 }
1213 }
1214 }
1215 }
96025800 1216
6a488035 1217}