Proceeding to confirmation page should be a "next" button not a check
[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.
6a488035 48 * CRM-7604
2dde9c7f 49 *
90b461f1 50 * @var bool
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
55d21031 394 $pps = $this->getProcessors();
aa288d3f 395 if ($this->getContactID() === 0 && !$this->_values['event']['is_multiple_registrations']) {
e1ce628e 396 //@todo we are blocking for multiple registrations because we haven't tested
f956cd24 397 $this->addCIDZeroOptions();
596bff78 398 }
6a488035
TO
399
400 if ($this->_values['event']['is_monetary']) {
1421b010 401 $this->addPaymentProcessorFieldsToForm();
6a488035
TO
402 }
403
be2fb01f 404 $this->addElement('hidden', 'bypass_payment', NULL, ['id' => 'bypass_payment']);
5ec4b965 405
6a488035 406 $this->assign('bypassPayment', $bypassPayment);
6a488035 407
5c280496 408 $userID = $this->getContactID();
6a488035
TO
409
410 if (!$userID) {
411 $createCMSUser = FALSE;
412
413 if ($this->_values['custom_pre_id']) {
414 $profileID = $this->_values['custom_pre_id'];
415 $createCMSUser = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'is_cms_user');
416 }
417
418 if (!$createCMSUser &&
419 $this->_values['custom_post_id']
420 ) {
421 if (!is_array($this->_values['custom_post_id'])) {
be2fb01f 422 $profileIDs = [$this->_values['custom_post_id']];
6a488035
TO
423 }
424 else {
425 $profileIDs = $this->_values['custom_post_id'];
426 }
427 foreach ($profileIDs as $pid) {
428 if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $pid, 'is_cms_user')) {
429 $profileID = $pid;
430 $createCMSUser = TRUE;
431 break;
432 }
433 }
434 }
435
436 if ($createCMSUser) {
437 CRM_Core_BAO_CMSUser::buildForm($this, $profileID, TRUE);
438 }
439 }
440
441 //we have to load confirm contribution button in template
442 //when multiple payment processor as the user
443 //can toggle with payment processor selection
444 $billingModePaymentProcessors = 0;
445 if (!CRM_Utils_System::isNull($this->_paymentProcessors)) {
446 foreach ($this->_paymentProcessors as $key => $values) {
447 if ($values['billing_mode'] == CRM_Core_Payment::BILLING_MODE_BUTTON) {
448 $billingModePaymentProcessors++;
449 }
450 }
451 }
452
453 if ($billingModePaymentProcessors && count($this->_paymentProcessors) == $billingModePaymentProcessors) {
454 $allAreBillingModeProcessors = TRUE;
0db6c3e1
TO
455 }
456 else {
6a488035
TO
457 $allAreBillingModeProcessors = FALSE;
458 }
459
8cc574cf 460 if (!$allAreBillingModeProcessors || !empty($this->_values['event']['is_pay_later']) || $bypassPayment
6a488035
TO
461 ) {
462
463 //freeze button to avoid multiple calls.
a7488080 464 if (empty($this->_values['event']['is_monetary'])) {
423616fa 465 $this->submitOnce = TRUE;
6a488035 466 }
2a6da8d7 467
1909126f 468 // CRM-11182 - Optional confirmation screen
469 // Change button label depending on whether the next action is confirm or register
1b9aa3aa
AH
470 $buttonParams = [
471 'type' => 'upload',
472 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
473 'isDefault' => TRUE,
474 ];
1909126f 475 if (
476 !$this->_values['event']['is_multiple_registrations']
d6121d3e 477 && !$this->_values['event']['is_monetary']
1909126f 478 && !$this->_values['event']['is_confirm_enabled']
479 ) {
1b9aa3aa 480 $buttonParams['name'] = ts('Register');
0db6c3e1
TO
481 }
482 else {
1b9aa3aa
AH
483 $buttonParams['name'] = ts('Review your registration');
484 $buttonParams['icon'] = 'fa-chevron-right';
1909126f 485 }
2a6da8d7 486
1b9aa3aa 487 $this->addButtons([$buttonParams]);
6a488035
TO
488 }
489
be2fb01f 490 $this->addFormRule(['CRM_Event_Form_Registration_Register', 'formRule'], $this);
86c0d461 491 $this->unsavedChangesWarn = TRUE;
6a488035
TO
492
493 // add pcp fields
494 if ($this->_pcpId) {
495 CRM_PCP_BAO_PCP::buildPcp($this->_pcpId, $this);
496 }
497 }
498
499 /**
100fef9d 500 * Build the radio/text form elements for the amount field
6a488035 501 *
0b36bfd7 502 * @param CRM_Event_Form_Registration_Register $form
d4dd1e85
TO
503 * Form object.
504 * @param bool $required
505 * True if you want to add formRule.
506 * @param int $discountId
507 * Discount id for the event.
2dde9c7f 508 *
509 * @throws \CRM_Core_Exception
6a488035 510 */
90b461f1 511 public static function buildAmount(&$form, $required = TRUE, $discountId = NULL) {
16d1c8e2 512 // build amount only when needed, skip incase of event full and waitlisting is enabled
513 // and few other conditions check preProcess()
a2a1e950 514 if (property_exists($form, '_noFees') && $form->_noFees) {
16d1c8e2 515 return;
516 }
517
6a488035 518 //if payment done, no need to build the fee block.
7bf9cde2 519 if (!empty($form->_paymentId)) {
b6e641a4 520 //fix to display line item in update mode.
2e1f50d6 521 $form->assign('priceSet', $form->_priceSet ?? NULL);
6a488035
TO
522 return;
523 }
524
9c1bc317 525 $feeFields = $form->_values['fee'] ?? NULL;
6a488035
TO
526
527 if (is_array($feeFields)) {
528 $form->_feeBlock = &$form->_values['fee'];
529 }
530
531 //check for discount.
9c1bc317 532 $discountedFee = $form->_values['discount'] ?? NULL;
6a488035
TO
533 if (is_array($discountedFee) && !empty($discountedFee)) {
534 if (!$discountId) {
535 $form->_discountId = $discountId = CRM_Core_BAO_Discount::findSet($form->_eventId, 'civicrm_event');
536 }
537 if ($discountId) {
538 $form->_feeBlock = &$form->_values['discount'][$discountId];
539 }
540 }
541 if (!is_array($form->_feeBlock)) {
be2fb01f 542 $form->_feeBlock = [];
6a488035
TO
543 }
544
545 //its time to call the hook.
546 CRM_Utils_Hook::buildAmount('event', $form, $form->_feeBlock);
547
548 //reset required if participant is skipped.
549 $button = substr($form->controller->getButtonName(), -4);
550 if ($required && $button == 'skip') {
551 $required = FALSE;
552 }
553
554 $className = CRM_Utils_System::getClassName($form);
555
556 //build the priceset fields.
557 if (isset($form->_priceSetId) && $form->_priceSetId) {
558
559 //format price set fields across option full.
560 self::formatFieldsForOptionFull($form);
561
a7488080 562 if (!empty($form->_priceSet['is_quick_config'])) {
6a488035
TO
563 $form->_quickConfig = $form->_priceSet['is_quick_config'];
564 }
565 $form->add('hidden', 'priceSetId', $form->_priceSetId);
566
c7b3d063 567 // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
ab8a593e 568 $adminFieldVisible = FALSE;
c7b3d063 569 if (CRM_Core_Permission::check('administer CiviCRM')) {
4eeb9a5b 570 $adminFieldVisible = TRUE;
c7b3d063
DG
571 }
572
a13c171d
CR
573 $hideAdminValues = TRUE;
574 if (CRM_Core_Permission::check('edit event participants')) {
575 $hideAdminValues = FALSE;
576 }
577
6a488035 578 foreach ($form->_feeBlock as $field) {
d06f3157 579 // public AND admin visibility fields are included for back-office registration and back-office change selections
6a488035 580 if (CRM_Utils_Array::value('visibility', $field) == 'public' ||
4eeb9a5b 581 (CRM_Utils_Array::value('visibility', $field) == 'admin' && $adminFieldVisible == TRUE) ||
d06f3157
DG
582 $className == 'CRM_Event_Form_Participant' ||
583 $className == 'CRM_Event_Form_ParticipantFeeSelection'
6a488035
TO
584 ) {
585 $fieldId = $field['id'];
586 $elementName = 'price_' . $fieldId;
587
9c1bc317 588 $isRequire = $field['is_required'] ?? NULL;
6a488035
TO
589 if ($button == 'skip') {
590 $isRequire = FALSE;
591 }
592
593 //user might modified w/ hook.
9c1bc317 594 $options = $field['options'] ?? NULL;
be2fb01f 595 $formClasses = ['CRM_Event_Form_Participant', 'CRM_Event_Form_ParticipantFeeSelection'];
a13c171d 596
6a488035
TO
597 if (!is_array($options)) {
598 continue;
599 }
a13c171d 600 elseif ($hideAdminValues && !in_array($className, $formClasses)) {
ad2785a2
CR
601 $publicVisibilityID = CRM_Price_BAO_PriceField::getVisibilityOptionID('public');
602 $adminVisibilityID = CRM_Price_BAO_PriceField::getVisibilityOptionID('admin');
603
a13c171d 604 foreach ($options as $key => $currentOption) {
ad2785a2
CR
605 $optionVisibility = CRM_Utils_Array::value('visibility_id', $currentOption, $publicVisibilityID);
606 if ($optionVisibility == $adminVisibilityID) {
a13c171d
CR
607 unset($options[$key]);
608 }
609 }
610 }
6a488035 611
be2fb01f 612 $optionFullIds = CRM_Utils_Array::value('option_full_ids', $field, []);
6a488035
TO
613
614 //soft suppress required rule when option is full.
615 if (!empty($optionFullIds) && (count($options) == count($optionFullIds))) {
616 $isRequire = FALSE;
617 }
1019b2fe
SL
618 if (!empty($options)) {
619 //build the element.
620 CRM_Price_BAO_PriceField::addQuickFormElement($form,
621 $elementName,
622 $fieldId,
623 FALSE,
624 $isRequire,
625 NULL,
626 $options,
627 $optionFullIds
628 );
629 }
6a488035
TO
630 }
631 }
632 $form->assign('priceSet', $form->_priceSet);
633 }
634 else {
be2fb01f 635 $eventFeeBlockValues = [];
6a488035
TO
636 foreach ($form->_feeBlock as $fee) {
637 if (is_array($fee)) {
638
639 //CRM-7632, CRM-6201
640 $totalAmountJs = NULL;
641 if ($className == 'CRM_Event_Form_Participant') {
be2fb01f 642 $totalAmountJs = ['onClick' => "fillTotalAmount(" . $fee['value'] . ")"];
6a488035
TO
643 }
644
645 $eventFeeBlockValues['amount_id_' . $fee['amount_id']] = $fee['value'];
646 $elements[] = &$form->createElement('radio', NULL, '',
647 CRM_Utils_Money::format($fee['value']) . ' ' .
648 $fee['label'],
649 $fee['amount_id'],
650 $totalAmountJs
651 );
652 }
653 }
654 $form->assign('eventFeeBlockValues', json_encode($eventFeeBlockValues));
655
9c1bc317 656 $form->_defaults['amount'] = $form->_values['event']['default_fee_id'] ?? NULL;
6a488035
TO
657 $element = &$form->addGroup($elements, 'amount', ts('Event Fee(s)'), '<br />');
658 if (isset($form->_online) && $form->_online) {
659 $element->freeze();
660 }
661 if ($required) {
662 $form->addRule('amount', ts('Fee Level is a required field.'), 'required');
663 }
664 }
665 }
666
0cf587a7 667 /**
0b36bfd7 668 * @param CRM_Event_Form_Registration $form
0cf587a7 669 */
6a488035
TO
670 public static function formatFieldsForOptionFull(&$form) {
671 $priceSet = $form->get('priceSet');
672 $priceSetId = $form->get('priceSetId');
be2fb01f 673 $defaultPricefieldIds = [];
e9bb507e 674 if (!empty($form->_values['line_items'])) {
675 foreach ($form->_values['line_items'] as $lineItem) {
676 $defaultPricefieldIds[] = $lineItem['price_field_value_id'];
677 }
678 }
6a488035
TO
679 if (!$priceSetId ||
680 !is_array($priceSet) ||
353ffa53
TO
681 empty($priceSet) || empty($priceSet['optionsMaxValueTotal'])
682 ) {
6a488035
TO
683 return;
684 }
685
be2fb01f 686 $skipParticipants = $formattedPriceSetDefaults = [];
e03317f1 687 if (!empty($form->_allowConfirmation) && (isset($form->_pId) || isset($form->_additionalParticipantId))) {
2e1f50d6 688 $participantId = $form->_pId ?? $form->_additionalParticipantId;
6a488035
TO
689 $pricesetDefaults = CRM_Event_Form_EventFees::setDefaultPriceSet($participantId,
690 $form->_eventId
691 );
692 // modify options full to respect the selected fields
693 // options on confirmation.
217d80ab 694 $formattedPriceSetDefaults = self::formatPriceSetParams($form, $pricesetDefaults);
6a488035
TO
695
696 // to skip current registered participants fields option count on confirmation.
697 $skipParticipants[] = $form->_participantId;
698 if (!empty($form->_additionalParticipantIds)) {
699 $skipParticipants = array_merge($skipParticipants, $form->_additionalParticipantIds);
700 }
701 }
702
703 $className = CRM_Utils_System::getClassName($form);
704
705 //get the current price event price set options count.
706 $currentOptionsCount = self::getPriceSetOptionCount($form);
707 $recordedOptionsCount = CRM_Event_BAO_Participant::priceSetOptionsCount($form->_eventId, $skipParticipants);
e9bb507e 708 $optionFullTotalAmount = 0;
0dc0b759 709 $currentParticipantNo = (int) substr($form->_name, 12);
6a488035 710 foreach ($form->_feeBlock as & $field) {
be2fb01f 711 $optionFullIds = [];
6a488035
TO
712 $fieldId = $field['id'];
713 if (!is_array($field['options'])) {
714 continue;
715 }
716 foreach ($field['options'] as & $option) {
353ffa53
TO
717 $optId = $option['id'];
718 $count = CRM_Utils_Array::value('count', $option, 0);
719 $maxValue = CRM_Utils_Array::value('max_value', $option, 0);
720 $dbTotalCount = CRM_Utils_Array::value($optId, $recordedOptionsCount, 0);
6a488035
TO
721 $currentTotalCount = CRM_Utils_Array::value($optId, $currentOptionsCount, 0);
722
79b152ac 723 $totalCount = $currentTotalCount + $dbTotalCount;
6a488035
TO
724 $isFull = FALSE;
725 if ($maxValue &&
0dc0b759 726 (($totalCount >= $maxValue) &&
727 (empty($form->_lineItem[$currentParticipantNo][$optId]['price_field_id']) || $dbTotalCount >= $maxValue))
6a488035
TO
728 ) {
729 $isFull = TRUE;
730 $optionFullIds[$optId] = $optId;
e9bb507e 731 if ($field['html_type'] != 'Select') {
732 if (in_array($optId, $defaultPricefieldIds)) {
733 $optionFullTotalAmount += CRM_Utils_Array::value('amount', $option);
734 }
735 }
736 else {
737 if (!empty($defaultPricefieldIds) && in_array($optId, $defaultPricefieldIds)) {
738 unset($optionFullIds[$optId]);
739 }
740 }
6a488035 741 }
6a488035
TO
742 //here option is not full,
743 //but we don't want to allow participant to increase
744 //seats at the time of re-walking registration.
745 if ($count &&
8dfe9fe3 746 !empty($form->_allowConfirmation) &&
6a488035
TO
747 !empty($formattedPriceSetDefaults)
748 ) {
217d80ab 749 if (empty($formattedPriceSetDefaults["price_{$field}"]) || empty($formattedPriceSetDefaults["price_{$fieldId}"][$optId])) {
6a488035
TO
750 $optionFullIds[$optId] = $optId;
751 $isFull = TRUE;
752 }
753 }
754 $option['is_full'] = $isFull;
755 $option['db_total_count'] = $dbTotalCount;
756 $option['total_option_count'] = $dbTotalCount + $currentTotalCount;
757 }
758
759 //ignore option full for offline registration.
760 if ($className == 'CRM_Event_Form_Participant') {
be2fb01f 761 $optionFullIds = [];
6a488035
TO
762 }
763
764 //finally get option ids in.
765 $field['option_full_ids'] = $optionFullIds;
766 }
e9bb507e 767 $form->assign('optionFullTotalAmount', $optionFullTotalAmount);
6a488035
TO
768 }
769
770 /**
66f9e52b 771 * Global form rule.
6a488035 772 *
d4dd1e85
TO
773 * @param array $fields
774 * The input form values.
775 * @param array $files
776 * The uploaded files if any.
22ef0f8e 777 * @param \CRM_Event_Form_Registration_Register $form
2a6da8d7 778 *
72b3a70c
CW
779 * @return bool|array
780 * true if no errors, else array of errors
2dde9c7f 781 *
782 * @throws \CRM_Core_Exception
6a488035 783 */
0b36bfd7 784 public static function formRule($fields, $files, $form) {
be2fb01f 785 $errors = [];
6a488035 786 //check that either an email or firstname+lastname is included in the form(CRM-9587)
0b36bfd7 787 self::checkProfileComplete($fields, $errors, $form->_eventId);
6a488035 788 //To check if the user is already registered for the event(CRM-2426)
0b36bfd7
MWMC
789 if (!$form->_skipDupeRegistrationCheck) {
790 self::checkRegistration($fields, $form);
6a488035
TO
791 }
792 //check for availability of registrations.
0b36bfd7
MWMC
793 if (!$form->_allowConfirmation && empty($fields['bypass_payment']) &&
794 is_numeric($form->_availableRegistrations) &&
795 CRM_Utils_Array::value('additional_participants', $fields) >= $form->_availableRegistrations
6a488035 796 ) {
be2fb01f 797 $errors['additional_participants'] = ts("There is only enough space left on this event for %1 participant(s).", [1 => $form->_availableRegistrations]);
6a488035
TO
798 }
799
89d51753 800 $numberAdditionalParticipants = $fields['additional_participants'] ?? 0;
801
802 if ($numberAdditionalParticipants && !CRM_Utils_Rule::positiveInteger($fields['additional_participants'])) {
803 $errors['additional_participants'] = ts('Please enter a whole number for Number of additional people.');
804 }
805
6a488035 806 // during confirmation don't allow to increase additional participants, CRM-4320
89d51753 807 if ($form->_allowConfirmation && $numberAdditionalParticipants &&
0b36bfd7 808 is_array($form->_additionalParticipantIds) &&
89d51753 809 $numberAdditionalParticipants > count($form->_additionalParticipantIds)
6a488035 810 ) {
be2fb01f 811 $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
812 }
813
814 //don't allow to register w/ waiting if enough spaces available.
0b36bfd7
MWMC
815 if (!empty($fields['bypass_payment']) && $form->_allowConfirmation) {
816 if (!is_numeric($form->_availableRegistrations) ||
817 (empty($fields['priceSetId']) && CRM_Utils_Array::value('additional_participants', $fields) < $form->_availableRegistrations)
6a488035
TO
818 ) {
819 $errors['bypass_payment'] = ts("Oops. There are enough available spaces in this event. You can not add yourself to the waiting list.");
820 }
821 }
822
6a488035 823 // priceset validations
0dc0b759 824 if (!empty($fields['priceSetId']) &&
0b36bfd7 825 !$form->_requireApproval && !$form->_allowWaitlist
0dc0b759 826 ) {
6a488035 827 //format params.
0b36bfd7 828 $formatted = self::formatPriceSetParams($form, $fields);
be2fb01f 829 $ppParams = [$formatted];
0b36bfd7
MWMC
830 $priceSetErrors = self::validatePriceSet($form, $ppParams);
831 $primaryParticipantCount = self::getParticipantCount($form, $ppParams);
6a488035
TO
832
833 //get price set fields errors in.
be2fb01f 834 $errors = array_merge($errors, CRM_Utils_Array::value(0, $priceSetErrors, []));
6a488035
TO
835
836 $totalParticipants = $primaryParticipantCount;
89d51753 837 if ($numberAdditionalParticipants) {
838 $totalParticipants += $numberAdditionalParticipants;
6a488035
TO
839 }
840
a7488080 841 if (empty($fields['bypass_payment']) &&
0b36bfd7
MWMC
842 !$form->_allowConfirmation &&
843 is_numeric($form->_availableRegistrations) &&
844 $form->_availableRegistrations < $totalParticipants
6a488035 845 ) {
be2fb01f 846 $errors['_qf_default'] = ts("Only %1 Registrations available.", [1 => $form->_availableRegistrations]);
6a488035
TO
847 }
848
be2fb01f 849 $lineItem = [];
0b36bfd7 850 CRM_Price_BAO_PriceSet::processAmount($form->_values['fee'], $fields, $lineItem);
601c7a24 851
852 $minAmt = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $fields['priceSetId'], 'min_amount');
6a488035
TO
853 if ($fields['amount'] < 0) {
854 $errors['_qf_default'] = ts('Event Fee(s) can not be less than zero. Please select the options accordingly');
855 }
601c7a24 856 elseif (!empty($minAmt) && $fields['amount'] < $minAmt) {
be2fb01f 857 $errors['_qf_default'] = ts('A minimum amount of %1 should be selected from Event Fee(s).', [
601c7a24 858 1 => CRM_Utils_Money::format($minAmt),
be2fb01f 859 ]);
601c7a24 860 }
6a488035 861 }
f2077611 862 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
863 if ($greetingType = CRM_Utils_Array::value($greeting, $fields)) {
864 $customizedValue = CRM_Core_PseudoConstant::getKey('CRM_Contact_BAO_Contact', $greeting . '_id', 'Customized');
865 if ($customizedValue == $greetingType && empty($fields[$greeting . '_custom'])) {
866 $errors[$greeting . '_custom'] = ts('Custom %1 is a required field if %1 is of type Customized.',
867 [1 => ucwords(str_replace('_', ' ', $greeting))]
868 );
869 }
870 }
871 }
6a488035 872
f48e6cf7 873 // @todo - can we remove the 'is_monetary' concept?
0b36bfd7
MWMC
874 if ($form->_values['event']['is_monetary']) {
875 if (empty($form->_requireApproval) && !empty($fields['amount']) && $fields['amount'] > 0 &&
1019b2fe 876 !isset($fields['payment_processor_id'])) {
e02d7e96 877 $errors['payment_processor_id'] = ts('Please select a Payment Method');
0d588131 878 }
6a488035 879
22ef0f8e 880 if (self::isZeroAmount($fields, $form)) {
881 return empty($errors) ? TRUE : $errors;
6a488035
TO
882 }
883
f48e6cf7 884 // also return if zero fees for valid members
885 if (!empty($fields['bypass_payment']) ||
0b36bfd7 886 (!$form->_allowConfirmation && ($form->_requireApproval || $form->_allowWaitlist))
6a488035
TO
887 ) {
888 return empty($errors) ? TRUE : $errors;
889 }
f48e6cf7 890 CRM_Core_Payment_Form::validatePaymentInstrument(
891 $fields['payment_processor_id'],
892 $fields,
893 $errors,
0b36bfd7 894 (!$form->_isBillingAddressRequiredForPayLater ? NULL : 'billing')
f48e6cf7 895 );
6a488035 896 }
6a488035 897
6a488035
TO
898 return empty($errors) ? TRUE : $errors;
899 }
900
901 /**
ec022878 902 * Check if profiles are complete when event registration occurs(CRM-9587).
903 *
904 * @param array $fields
905 * @param array $errors
906 * @param int $eventId
6a488035 907 */
00be9182 908 public static function checkProfileComplete($fields, &$errors, $eventId) {
6a488035
TO
909 $email = '';
910 foreach ($fields as $fieldname => $fieldvalue) {
911 if (substr($fieldname, 0, 6) == 'email-' && $fieldvalue) {
912 $email = $fieldvalue;
913 }
914 }
915
8cc574cf 916 if (!$email && !(!empty($fields['first_name']) && !empty($fields['last_name']))) {
be2fb01f 917 $defaults = $params = ['id' => $eventId];
6a488035
TO
918 CRM_Event_BAO_Event::retrieve($params, $defaults);
919 $message = ts("Mandatory fields (first name and last name, OR email address) are missing from this form.");
920 $errors['_qf_default'] = $message;
921 }
922 }
923
924 /**
66f9e52b 925 * Process the form submission.
6a488035
TO
926 */
927 public function postProcess() {
928 // get the submitted form values.
929 $params = $this->controller->exportValues($this->_name);
930
931 //set as Primary participant
932 $params['is_primary'] = 1;
933
8ae4d0d3 934 if ($this->_values['event']['is_pay_later']
e02d7e96 935 && (!array_key_exists('hidden_processor', $params) || $params['payment_processor_id'] == 0)
353ffa53 936 ) {
6a488035
TO
937 $params['is_pay_later'] = 1;
938 }
939 else {
940 $params['is_pay_later'] = 0;
941 }
942
943 $this->set('is_pay_later', $params['is_pay_later']);
944
945 // assign pay later stuff
946 $this->_params['is_pay_later'] = CRM_Utils_Array::value('is_pay_later', $params, FALSE);
947 $this->assign('is_pay_later', $params['is_pay_later']);
948 if ($params['is_pay_later']) {
949 $this->assign('pay_later_text', $this->_values['event']['pay_later_text']);
950 $this->assign('pay_later_receipt', $this->_values['event']['pay_later_receipt']);
951 }
6a488035 952
168e792f
DL
953 if (!$this->_allowConfirmation) {
954 // check if the participant is already registered
955 if (!$this->_skipDupeRegistrationCheck) {
7dfe13ab 956 $params['contact_id'] = self::getRegistrationContactID($params, $this, FALSE);
168e792f
DL
957 }
958 }
959
a7488080 960 if (!empty($params['image_URL'])) {
6a488035
TO
961 CRM_Contact_BAO_Contact::processImageParams($params);
962 }
963
964 //carry campaign to partcipants.
965 if (array_key_exists('participant_campaign_id', $params)) {
966 $params['campaign_id'] = $params['participant_campaign_id'];
967 }
968 else {
9c1bc317 969 $params['campaign_id'] = $this->_values['event']['campaign_id'] ?? NULL;
6a488035
TO
970 }
971
972 //hack to allow group to register w/ waiting
973 $primaryParticipantCount = self::getParticipantCount($this, $params);
974
975 $totalParticipants = $primaryParticipantCount;
a7488080 976 if (!empty($params['additional_participants'])) {
6a488035
TO
977 $totalParticipants += $params['additional_participants'];
978 }
8cc574cf 979 if (!$this->_allowConfirmation && !empty($params['bypass_payment']) &&
6a488035
TO
980 is_numeric($this->_availableRegistrations) &&
981 $totalParticipants > $this->_availableRegistrations
982 ) {
983 $this->_allowWaitlist = TRUE;
984 $this->set('allowWaitlist', TRUE);
985 }
986
987 //carry participant id if pre-registered.
988 if ($this->_allowConfirmation && $this->_participantId) {
989 $params['participant_id'] = $this->_participantId;
990 }
991
992 $params['defaultRole'] = 1;
993 if (array_key_exists('participant_role', $params)) {
994 $params['participant_role_id'] = $params['participant_role'];
995 }
996
997 if (array_key_exists('participant_role_id', $params)) {
998 $params['defaultRole'] = 0;
999 }
a7488080 1000 if (empty($params['participant_role_id']) &&
6a488035
TO
1001 $this->_values['event']['default_role_id']
1002 ) {
1003 $params['participant_role_id'] = $this->_values['event']['default_role_id'];
1004 }
1005
1006 $config = CRM_Core_Config::singleton();
1007 $params['currencyID'] = $config->defaultCurrency;
1008
1009 if ($this->_values['event']['is_monetary']) {
1010 // we first reset the confirm page so it accepts new values
1011 $this->controller->resetPage('Confirm');
1012
1013 //added for discount
1014 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
c039f658 1015 $params['amount_level'] = $this->getAmountLevel($params, $discountId);
6a488035
TO
1016 if (!empty($this->_values['discount'][$discountId])) {
1017 $params['discount_id'] = $discountId;
6a488035
TO
1018 $params['amount'] = $this->_values['discount'][$discountId][$params['amount']]['value'];
1019 }
1020 elseif (empty($params['priceSetId'])) {
16d1c8e2 1021 if (!empty($params['amount'])) {
16d1c8e2 1022 $params['amount'] = $this->_values['fee'][$params['amount']]['value'];
1023 }
1024 else {
c039f658 1025 $params['amount'] = '';
16d1c8e2 1026 }
6a488035
TO
1027 }
1028 else {
be2fb01f 1029 $lineItem = [];
9da8dc8c 1030 CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem);
d91b8b33 1031 if ($params['tax_amount']) {
1032 $this->set('tax_amount', $params['tax_amount']);
1033 }
9d8d8fd0 1034 $submittedLineItems = $this->get('lineItem');
1035 if (!empty($submittedLineItems) && is_array($submittedLineItems)) {
0dc0b759 1036 $submittedLineItems[0] = $lineItem;
1037 }
1038 else {
be2fb01f 1039 $submittedLineItems = [$lineItem];
0dc0b759 1040 }
dba6436f 1041 $submittedLineItems = array_filter($submittedLineItems);
0dc0b759 1042 $this->set('lineItem', $submittedLineItems);
be2fb01f 1043 $this->set('lineItemParticipantsCount', [$primaryParticipantCount]);
6a488035
TO
1044 }
1045
1046 $this->set('amount', $params['amount']);
1047 $this->set('amount_level', $params['amount_level']);
1048
1049 // generate and set an invoiceID for this transaction
1050 $invoiceID = md5(uniqid(rand(), TRUE));
1051 $this->set('invoiceID', $invoiceID);
1052
b0c462ac 1053 if ($this->_paymentProcessor) {
077017db 1054 $payment = $this->_paymentProcessor['object'];
ec022878 1055 $payment->setBaseReturnUrl('civicrm/event/register');
6a488035 1056 }
0eb1f7ff 1057
1058 // ContributeMode is a deprecated concept. It is short-hand for a bunch of
1059 // assumptions we are working to remove.
6a488035
TO
1060 $this->set('contributeMode', 'direct');
1061
6a488035 1062 if ($this->_values['event']['is_monetary']) {
6a488035 1063 $params['currencyID'] = $config->defaultCurrency;
6a488035
TO
1064 $params['invoiceID'] = $invoiceID;
1065 }
d0ebccea 1066 $this->_params = $this->get('params');
ec022878 1067 // Set the button so we know what
1068 $params['button'] = $this->controller->getButtonName();
d0ebccea 1069 if (!empty($this->_params) && is_array($this->_params)) {
0dc0b759 1070 $this->_params[0] = $params;
1071 }
1072 else {
be2fb01f 1073 $this->_params = [];
0dc0b759 1074 $this->_params[] = $params;
1075 }
6a488035 1076 $this->set('params', $this->_params);
f92fc7eb 1077 if ($this->_paymentProcessor &&
223190c8 1078 // Actually we don't really need to check if it supports pre-approval - we could just call
1079 // it regardless as the function we call re-acts tot the rests of the preApproval call.
ec022878 1080 $this->_paymentProcessor['object']->supports('preApproval')
1081 && !$this->_allowWaitlist &&
1082 !$this->_requireApproval
f92fc7eb 1083 ) {
6a488035 1084
0f2b049e 1085 // The concept of contributeMode is deprecated - but still needs removal from the message templates.
ec022878 1086 $this->set('contributeMode', 'express');
6a488035 1087
ec022878 1088 // Send Event Name & Id in Params
1089 $params['eventName'] = $this->_values['event']['title'];
1090 $params['eventId'] = $this->_values['event']['id'];
6a488035 1091
ec022878 1092 $params['cancelURL'] = CRM_Utils_System::url('civicrm/event/register',
1093 "_qf_Register_display=1&qfKey={$this->controller->_key}",
1094 TRUE, NULL, FALSE
1095 );
de6c59ca 1096 if (!empty($params['additional_participants'])) {
ec022878 1097 $urlArgs = "_qf_Participant_1_display=1&rfp=1&qfKey={$this->controller->_key}";
1098 }
1099 else {
1100 $urlArgs = "_qf_Confirm_display=1&rfp=1&qfKey={$this->controller->_key}";
1101 }
1102 $params['returnURL'] = CRM_Utils_System::url('civicrm/event/register',
1103 $urlArgs,
1104 TRUE, NULL, FALSE
1105 );
1106 $params['invoiceID'] = $invoiceID;
6a488035 1107
ec022878 1108 $params['component'] = 'event';
1a093d07 1109 // This code is duplicated multiple places and should be consolidated.
1110 $params = $this->prepareParamsForPaymentProcessor($params);
223190c8 1111 $this->handlePreApproval($params);
6a488035 1112 }
f92fc7eb 1113 elseif ($this->_paymentProcessor &&
5e3148f4 1114 (int) $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY
f92fc7eb 1115 ) {
0f2b049e 1116 // The concept of contributeMode is deprecated - but still needs removal from the message templates.
6a488035
TO
1117 $this->set('contributeMode', 'notify');
1118 }
13f230bc 1119 }
1120 else {
1121 $params['description'] = ts('Online Event Registration') . ' ' . $this->_values['event']['title'];
6a488035 1122
be2fb01f 1123 $this->_params = [];
13f230bc 1124 $this->_params[] = $params;
1125 $this->set('params', $this->_params);
6a488035 1126
13f230bc 1127 if (
1128 empty($params['additional_participants'])
90b461f1
SL
1129 // CRM-11182 - Optional confirmation screen
1130 && !$this->_values['event']['is_confirm_enabled']
13f230bc 1131 ) {
3033e657 1132 $this->processRegistration($this->_params);
6a488035
TO
1133 }
1134 }
1135
1136 // If registering > 1 participant, give status message
de6c59ca 1137 if (!empty($params['additional_participants'])) {
6a488035
TO
1138 $statusMsg = ts('Registration information for participant 1 has been saved.');
1139 CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success');
1140 }
1141 }
6a488035 1142
6a488035 1143 /**
66f9e52b 1144 * Method to check if the user is already registered for the event.
6a488035
TO
1145 * and if result found redirect to the event info page
1146 *
d4dd1e85
TO
1147 * @param array $fields
1148 * The input form values(anonymous user).
0b36bfd7 1149 * @param CRM_Event_Form_Registration_Register $form
d4dd1e85
TO
1150 * Event data.
1151 * @param bool $isAdditional
1152 * Treat isAdditional participants a bit differently.
6a488035 1153 *
54957108 1154 * @return int
6a488035 1155 */
0b36bfd7 1156 public static function checkRegistration($fields, $form, $isAdditional = FALSE) {
6a488035
TO
1157 // CRM-3907, skip check for preview registrations
1158 // CRM-4320 participant need to walk wizard
7dfe13ab 1159 if (
0b36bfd7 1160 ($form->_mode == 'test' || $form->_allowConfirmation)
6a488035
TO
1161 ) {
1162 return FALSE;
1163 }
1164
0b36bfd7 1165 $contactID = self::getRegistrationContactID($fields, $form, $isAdditional);
6a488035 1166
6a488035
TO
1167 if ($contactID) {
1168 $participant = new CRM_Event_BAO_Participant();
1169 $participant->contact_id = $contactID;
0b36bfd7 1170 $participant->event_id = $form->_values['event']['id'];
6a488035
TO
1171 if (!empty($fields['participant_role']) && is_numeric($fields['participant_role'])) {
1172 $participant->role_id = $fields['participant_role'];
1173 }
1174 else {
0b36bfd7 1175 $participant->role_id = $form->_values['event']['default_role_id'];
6a488035
TO
1176 }
1177 $participant->is_test = 0;
1178 $participant->find();
ed66ac46
JG
1179 // Event#30 - Anyone whose status type has `is_counted` OR is on the waitlist should be considered as registered.
1180 $statusTypes = CRM_Event_PseudoConstant::participantStatus(NULL, 'is_counted = 1') + CRM_Event_PseudoConstant::participantStatus(NULL, "name = 'On waitlist'");
6a488035
TO
1181 while ($participant->fetch()) {
1182 if (array_key_exists($participant->status_id, $statusTypes)) {
0b36bfd7 1183 if (!$isAdditional && !$form->_values['event']['allow_same_participant_emails']) {
6a488035 1184 $registerUrl = CRM_Utils_System::url('civicrm/event/register',
0b36bfd7 1185 "reset=1&id={$form->_values['event']['id']}&cid=0"
6a488035 1186 );
0b36bfd7
MWMC
1187 if ($form->_pcpId) {
1188 $registerUrl .= '&pcpId=' . $form->_pcpId;
6a488035 1189 }
ed66ac46
JG
1190 $registrationType = (CRM_Event_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'participant_status_id', 'On waitlist') == $participant->status_id) ? 'waitlisted' : 'registered';
1191 $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]);
1192 $status .= ' ' . ts('You can also <a href="%1">register another participant</a>.', [1 => $registerUrl]);
7dfe13ab 1193 CRM_Core_Session::singleton()->setStatus($status, ts('Oops.'), 'alert');
6a488035 1194 $url = CRM_Utils_System::url('civicrm/event/info',
0b36bfd7 1195 "reset=1&id={$form->_values['event']['id']}&noFullMsg=true"
6a488035 1196 );
0b36bfd7 1197 if ($form->_action & CRM_Core_Action::PREVIEW) {
6a488035
TO
1198 $url .= '&action=preview';
1199 }
1200
0b36bfd7
MWMC
1201 if ($form->_pcpId) {
1202 $url .= '&pcpId=' . $form->_pcpId;
6a488035
TO
1203 }
1204
1205 CRM_Utils_System::redirect($url);
1206 }
1207
1208 if ($isAdditional) {
06141953 1209 $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 1210 CRM_Core_Session::singleton()->setStatus($status, ts('Oops.'), 'alert');
6a488035
TO
1211 return $participant->id;
1212 }
1213 }
1214 }
1215 }
1216 }
96025800 1217
6a488035 1218}