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