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