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