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