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