Merge pull request #23207 from braders/row-action-nodefaults
[civicrm-core.git] / CRM / Event / Form / Registration / AdditionalParticipant.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/**
13 *
14 *
15 * @package CRM
ca5cec67 16 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
17 */
18
19/**
c039f658 20 * This class generates form components for processing Event.
6a488035
TO
21 */
22class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_Registration {
23
6a488035 24 /**
100fef9d 25 * Pre-registered additional participant id.
90b461f1 26 * @var int
6a488035
TO
27 */
28 public $additionalParticipantId = NULL;
29
1ebb7282
MW
30 /**
31 * Get the active UFGroups (profiles) on this form
32 * Many forms load one or more UFGroups (profiles).
33 * This provides a standard function to retrieve the IDs of those profiles from the form
34 * so that you can implement things such as "is is_captcha field set on any of the active profiles on this form?"
35 *
36 * NOT SUPPORTED FOR USE OUTSIDE CORE EXTENSIONS - Added for reCAPTCHA core extension.
37 *
38 * @return array
39 */
40 public function getUFGroupIDs() {
41 $ufGroupIDs = [];
42 foreach (['pre', 'post'] as $keys) {
43 if (isset($this->_values['additional_custom_' . $keys . '_id'])) {
44 $ufGroupIDs[] = $this->_values['additional_custom_' . $keys . '_id'];
45 }
46 }
47 return $ufGroupIDs;
48 }
49
6a488035 50 /**
66f9e52b 51 * Set variables up before form is built.
6a488035
TO
52 *
53 * @return void
6a488035 54 */
00be9182 55 public function preProcess() {
6a488035
TO
56 parent::preProcess();
57
58 $participantNo = substr($this->_name, 12);
59
60 //lets process in-queue participants.
61 if ($this->_participantId && $this->_additionalParticipantIds) {
9c1bc317 62 $this->_additionalParticipantId = $this->_additionalParticipantIds[$participantNo] ?? NULL;
6a488035
TO
63 }
64
65 $participantCnt = $participantNo + 1;
66 $this->assign('formId', $participantNo);
be2fb01f 67 $this->_params = [];
6a488035
TO
68 $this->_params = $this->get('params');
69
70 $participantTot = $this->_params[0]['additional_participants'] + 1;
71 $skipCount = count(array_keys($this->_params, "skip"));
72 if ($skipCount) {
73 $this->assign('skipCount', $skipCount);
74 }
94fd9d17 75 $this->setTitle(ts('Register Participant %1 of %2', [1 => $participantCnt, 2 => $participantTot]));
6a488035
TO
76
77 //CRM-4320, hack to check last participant.
78 $this->_lastParticipant = FALSE;
79 if ($participantTot == $participantCnt) {
80 $this->_lastParticipant = TRUE;
81 }
82 $this->assign('lastParticipant', $this->_lastParticipant);
83 }
84
85 /**
c490a46a 86 * Set default values for the form. For edit/view mode
6a488035
TO
87 * the default values are retrieved from the database
88 *
6a488035 89 *
355ba699 90 * @return void
6a488035 91 */
00be9182 92 public function setDefaultValues() {
be2fb01f 93 $defaults = $unsetSubmittedOptions = [];
6a488035
TO
94 $discountId = NULL;
95 //fix for CRM-3088, default value for discount set.
96 if (!empty($this->_values['discount'])) {
97 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
8cc574cf 98 if ($discountId && !empty($this->_values['event']['default_discount_fee_id'])) {
0479b4c8 99 $discountKey = CRM_Core_DAO::getFieldValue("CRM_Core_DAO_OptionValue", $this->_values['event']['default_discount_fee_id'], 'weight', 'id'
6a488035
TO
100 );
101 $defaults['amount'] = key(array_slice($this->_values['discount'][$discountId], $discountKey - 1, $discountKey, TRUE));
102 }
103 }
104 if ($this->_priceSetId) {
105 foreach ($this->_feeBlock as $key => $val) {
a7488080 106 if (empty($val['options'])) {
6a488035
TO
107 continue;
108 }
109
be2fb01f 110 $optionsFull = CRM_Utils_Array::value('option_full_ids', $val, []);
6a488035
TO
111 foreach ($val['options'] as $keys => $values) {
112 if ($values['is_default'] && !in_array($keys, $optionsFull)) {
113 if ($val['html_type'] == 'CheckBox') {
114 $defaults["price_{$key}"][$keys] = 1;
115 }
116 else {
117 $defaults["price_{$key}"] = $keys;
118 }
119 }
120 }
121 if (!empty($optionsFull)) {
122 $unsetSubmittedOptions[$val['id']] = $optionsFull;
123 }
124 }
125 }
126
127 //CRM-4320, setdefault additional participant values.
128 if ($this->_allowConfirmation && $this->_additionalParticipantId) {
129 //hack to get set default from eventFees.php
353ffa53
TO
130 $this->_discountId = $discountId;
131 $this->_pId = $this->_additionalParticipantId;
132 $this->_contactId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $this->_additionalParticipantId, 'contact_id');
c7d52684 133
134 CRM_Event_BAO_Participant::formatFieldsAndSetProfileDefaults($this->_contactId, $this);
6a488035
TO
135 $participantDefaults = CRM_Event_Form_EventFees::setDefaultValues($this);
136 $participantDefaults = array_merge($this->_defaults, $participantDefaults);
137 // use primary email address if billing email address is empty
138 if (empty($this->_defaults["email-{$this->_bltID}"]) &&
139 !empty($this->_defaults["email-Primary"])
140 ) {
141 $participantDefaults["email-{$this->_bltID}"] = $this->_defaults["email-Primary"];
142 }
143 $defaults = array_merge($defaults, $participantDefaults);
144 }
145
146 $defaults = array_merge($this->_defaults, $defaults);
147
148 //reset values for all options those are full.
0dc0b759 149 CRM_Event_Form_Registration::resetElementValue($unsetSubmittedOptions, $this);
6a488035
TO
150
151 //load default campaign from page.
152 if (array_key_exists('participant_campaign_id', $this->_fields)) {
9c1bc317 153 $defaults['participant_campaign_id'] = $this->_values['event']['campaign_id'] ?? NULL;
6a488035 154 }
6a488035 155
dde86037
BS
156 //CRM-17865 set custom field defaults
157 if (!empty($this->_fields)) {
158 foreach ($this->_fields as $name => $field) {
159 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
160 if (!isset($defaults[$name])) {
161 CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, $name, $defaults,
162 NULL, CRM_Profile_Form::MODE_REGISTER
163 );
164 }
165 }
166 }
167 }
168
6a488035
TO
169 return $defaults;
170 }
171
172 /**
66f9e52b 173 * Build the form object.
6a488035 174 *
355ba699 175 * @return void
6a488035
TO
176 */
177 public function buildQuickForm() {
5f39c1a6 178
6a488035
TO
179 $button = substr($this->controller->getButtonName(), -4);
180
6a488035
TO
181 if ($this->_values['event']['is_monetary']) {
182 CRM_Event_Form_Registration_Register::buildAmount($this);
183 }
6a488035 184
60b661ac
JP
185 //Add pre and post profiles on the form.
186 foreach (['pre', 'post'] as $keys) {
187 if (isset($this->_values['additional_custom_' . $keys . '_id'])) {
188 $this->buildCustom($this->_values['additional_custom_' . $keys . '_id'], 'additionalCustom' . ucfirst($keys));
189 }
190 }
191
6a488035 192 //add buttons
8cc574cf 193 if ($this->isLastParticipant(TRUE) && empty($this->_values['event']['is_monetary'])) {
423616fa 194 $this->submitOnce = TRUE;
6a488035
TO
195 }
196
197 //handle case where user might sart with waiting by group
198 //registration and skip some people and now group fit to
199 //become registered so need to take payment from user.
200 //this case only occurs at dynamic waiting status, CRM-4320
201 $statusMessage = NULL;
202 $allowToProceed = TRUE;
203 $includeSkipButton = TRUE;
204 $this->_resetAllowWaitlist = FALSE;
205
9da8dc8c 206 $pricesetFieldsCount = CRM_Price_BAO_PriceSet::getPricesetCount($this->_priceSetId);
6a488035
TO
207
208 if ($this->_lastParticipant || $pricesetFieldsCount) {
209 //get the participant total.
210 $processedCnt = self::getParticipantCount($this, $this->_params, TRUE);
211 }
212
8cc574cf 213 if (!$this->_allowConfirmation && !empty($this->_params[0]['bypass_payment']) &&
6a488035
TO
214 $this->_lastParticipant
215 ) {
216
217 //get the event spaces.
218 $spaces = $this->_availableRegistrations;
219
220 $currentPageMaxCount = 1;
221 if ($pricesetFieldsCount) {
222 $currentPageMaxCount = $pricesetFieldsCount;
223 }
224
225 //we might did reset allow waiting in case of dynamic calculation
5f39c1a6 226 // @TODO - does this bypass_payment still exist?
a7488080 227 if (!empty($this->_params[0]['bypass_payment']) &&
6a488035
TO
228 is_numeric($spaces) &&
229 $processedCnt > $spaces
230 ) {
231 $this->_allowWaitlist = TRUE;
232 $this->set('allowWaitlist', TRUE);
233 }
234
235 //lets allow to become a part of runtime waiting list, if primary selected pay later.
236 $realPayLater = FALSE;
8cc574cf 237 if (!empty($this->_values['event']['is_monetary']) && !empty($this->_values['event']['is_pay_later'])) {
9c1bc317 238 $realPayLater = $this->_params[0]['is_pay_later'] ?? NULL;
6a488035
TO
239 }
240
241 //truly spaces are greater than required.
242 if (is_numeric($spaces) && $spaces >= ($processedCnt + $currentPageMaxCount)) {
243 if (CRM_Utils_Array::value('amount', $this->_params[0], 0) == 0 || $this->_requireApproval) {
244 $this->_allowWaitlist = FALSE;
245 $this->set('allowWaitlist', $this->_allowWaitlist);
246 if ($this->_requireApproval) {
be2fb01f 247 $statusMessage = ts("It looks like you are now registering a group of %1 participants. The event has %2 available spaces (you will not be wait listed). Registration for this event requires approval. You will receive an email once your registration has been reviewed.", [
90b461f1
SL
248 1 => ++$processedCnt,
249 2 => $spaces,
250 ]);
6a488035
TO
251 }
252 else {
be2fb01f 253 $statusMessage = ts("It looks like you are now registering a group of %1 participants. The event has %2 available spaces (you will not be wait listed).", [
90b461f1
SL
254 1 => ++$processedCnt,
255 2 => $spaces,
256 ]);
6a488035
TO
257 }
258 }
259 else {
be2fb01f 260 $statusMessage = ts("It looks like you are now registering a group of %1 participants. The event has %2 available spaces (you will not be wait listed). Please go back to the main registration page and reduce the number of additional people. You will also need to complete payment information.", [
90b461f1
SL
261 1 => ++$processedCnt,
262 2 => $spaces,
263 ]);
6a488035
TO
264 $allowToProceed = FALSE;
265 }
266 CRM_Core_Session::setStatus($statusMessage, ts('Registration Error'), 'error');
267 }
268 elseif ($processedCnt == $spaces) {
269 if (CRM_Utils_Array::value('amount', $this->_params[0], 0) == 0
270 || $realPayLater || $this->_requireApproval
271 ) {
272 $this->_resetAllowWaitlist = TRUE;
273 if ($this->_requireApproval) {
274 $statusMessage = ts("If you skip this participant there will be enough spaces in the event for your group (you will not be wait listed). Registration for this event requires approval. You will receive an email once your registration has been reviewed.");
275 }
276 else {
277 $statusMessage = ts("If you skip this participant there will be enough spaces in the event for your group (you will not be wait listed).");
278 }
279 }
280 else {
281 //hey there is enough space and we require payment.
282 $statusMessage = ts("If you skip this participant there will be enough spaces in the event for your group (you will not be wait listed). Please go back to the main registration page and reduce the number of additional people. You will also need to complete payment information.");
283 $includeSkipButton = FALSE;
284 }
285 }
286 }
287
288 // for priceset with count
8cc574cf 289 if ($pricesetFieldsCount && !empty($this->_values['event']['has_waitlist']) &&
6a488035
TO
290 !$this->_allowConfirmation
291 ) {
292
293 if ($this->_isEventFull) {
294 $statusMessage = ts('This event is currently full. You are registering for the waiting list. You will be notified if spaces become available.');
295 }
296 elseif ($this->_allowWaitlist ||
297 (!$this->_allowWaitlist && ($processedCnt + $pricesetFieldsCount) > $this->_availableRegistrations)
298 ) {
299
300 $waitingMsg = ts('It looks like you are registering more participants then there are spaces available. All participants will be added to the waiting list. You will be notified if spaces become available.');
301 $confirmedMsg = ts('It looks like there are enough spaces in this event for your group (you will not be wait listed).');
302 if ($this->_requireApproval) {
303 $waitingMsg = ts('It looks like you are now registering a group of %1 participants. The event has %2 available spaces (you will not be wait listed). Registration for this event requires approval. You will receive an email once your registration has been reviewed.');
304 $confirmedMsg = ts('It looks there are enough spaces in this event for your group (you will not be wait listed). Registration for this event requires approval. You will receive an email once your registration has been reviewed.');
305 }
306
307 $this->assign('waitingMsg', $waitingMsg);
308 $this->assign('confirmedMsg', $confirmedMsg);
309
310 $this->assign('availableRegistrations', $this->_availableRegistrations);
311 $this->assign('currentParticipantCount', $processedCnt);
312 $this->assign('allowGroupOnWaitlist', TRUE);
313
314 $paymentBypassed = NULL;
a7488080 315 if (!empty($this->_params[0]['bypass_payment']) &&
6a488035
TO
316 !$this->_allowWaitlist &&
317 !$realPayLater &&
318 !$this->_requireApproval &&
319 !(CRM_Utils_Array::value('amount', $this->_params[0], 0) == 0)
320 ) {
321 $paymentBypassed = ts('Please go back to the main registration page, to complete payment information.');
322 }
323 $this->assign('paymentBypassed', $paymentBypassed);
324 }
325 }
326
327 $this->assign('statusMessage', $statusMessage);
328
be2fb01f
CW
329 $buttons = [
330 [
f212d37d
CW
331 'type' => 'back',
332 'name' => ts('Go Back'),
6a488035 333 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp',
be2fb01f
CW
334 ],
335 ];
6a488035
TO
336
337 //CRM-4320
338 if ($allowToProceed) {
be2fb01f 339 $buttons = array_merge($buttons, [
90b461f1
SL
340 [
341 'type' => 'upload',
342 'name' => ts('Continue'),
343 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
344 'isDefault' => TRUE,
90b461f1
SL
345 ],
346 ]);
6a488035 347 if ($includeSkipButton) {
be2fb01f 348 $buttons = array_merge($buttons, [
90b461f1
SL
349 [
350 'type' => 'next',
351 'name' => ts('Skip Participant'),
352 'subName' => 'skip',
353 'icon' => 'fa-fast-forward',
354 ],
355 ]);
6a488035
TO
356 }
357 }
358 $this->addButtons($buttons);
be2fb01f 359 $this->addFormRule(['CRM_Event_Form_Registration_AdditionalParticipant', 'formRule'], $this);
86c0d461 360 $this->unsavedChangesWarn = TRUE;
6a488035
TO
361 }
362
363 /**
66f9e52b 364 * Global form rule.
6a488035 365 *
d4dd1e85
TO
366 * @param array $fields
367 * The input form values.
368 * @param array $files
369 * The uploaded files if any.
e8cf95b4 370 * @param self $self
77b97be7 371 *
6a488035 372 *
72b3a70c
CW
373 * @return bool|array
374 * true if no errors, else array of errors
6a488035 375 */
00be9182 376 public static function formRule($fields, $files, $self) {
be2fb01f 377 $errors = [];
6a488035
TO
378 //get the button name.
379 $button = substr($self->controller->getButtonName(), -4);
380
381 $realPayLater = FALSE;
8cc574cf 382 if (!empty($self->_values['event']['is_monetary']) && !empty($self->_values['event']['is_pay_later'])) {
9c1bc317 383 $realPayLater = $self->_params[0]['is_pay_later'] ?? NULL;
6a488035
TO
384 }
385
386 if ($button != 'skip') {
387 //Check that either an email or firstname+lastname is included in the form(CRM-9587)
388 CRM_Event_Form_Registration_Register::checkProfileComplete($fields, $errors, $self->_eventId);
389
390 //Additional Participant can also register for an event only once
391 $isRegistered = CRM_Event_Form_Registration_Register::checkRegistration($fields, $self, TRUE);
392 if ($isRegistered) {
393 if ($self->_values['event']['allow_same_participant_emails']) {
394 $errors['_qf_default'] = ts('A person is already registered for this event.');
395 }
396 else {
397 $errors["email-{$self->_bltID}"] = ts('A person with this email address is already registered for this event.');
398 }
399 }
400
401 //get the complete params.
402 $params = $self->get('params');
403
404 //take the participant instance.
405 $addParticipantNum = substr($self->_name, 12);
406
407 if (is_array($params)) {
408 foreach ($params as $key => $value) {
409 if ($key != $addParticipantNum) {
410 if (!$self->_values['event']['allow_same_participant_emails']) {
411 //collect all email fields
be2fb01f
CW
412 $existingEmails = [];
413 $additionalParticipantEmails = [];
6a488035 414 if (is_array($value)) {
0479b4c8
TO
415 foreach ($value as $key => $val) {
416 if (substr($key, 0, 6) == 'email-' && $val) {
417 $existingEmails[] = $val;
418 }
6a488035
TO
419 }
420 }
6a488035
TO
421 foreach ($fields as $key => $val) {
422 if (substr($key, 0, 6) == 'email-' && $val) {
423 $additionalParticipantEmails[] = $val;
424 $mailKey = $key;
425 }
426 }
427 //check if any emails are common to both arrays
428 if (count(array_intersect($existingEmails, $additionalParticipantEmails))) {
429 $errors[$mailKey] = ts('The email address must be unique for each participant.');
430 break;
431 }
432 }
433 else {
434 // check with first_name and last_name for additional participants
33ab1d69 435 if (!empty($value['first_name']) && ($value['first_name'] == CRM_Utils_Array::value('first_name', $fields)) &&
0479b4c8 436 (CRM_Utils_Array::value('last_name', $value) == CRM_Utils_Array::value('last_name', $fields))
6a488035
TO
437 ) {
438 $errors['first_name'] = ts('The first name and last name must be unique for each participant.');
439 break;
440 }
441 }
442 }
443 }
444 }
445
446 //check for atleast one pricefields should be selected
a7488080 447 if (!empty($fields['priceSetId'])) {
6a488035
TO
448 $allParticipantParams = $params;
449
450 //format current participant params.
451 $allParticipantParams[$addParticipantNum] = self::formatPriceSetParams($self, $fields);
452 $totalParticipants = self::getParticipantCount($self, $allParticipantParams);
453
454 //validate price field params.
455 $priceSetErrors = self::validatePriceSet($self, $allParticipantParams);
be2fb01f 456 $errors = array_merge($errors, CRM_Utils_Array::value($addParticipantNum, $priceSetErrors, []));
6a488035
TO
457
458 if (!$self->_allowConfirmation &&
459 is_numeric($self->_availableRegistrations)
460 ) {
a7488080 461 if (!empty($self->_params[0]['bypass_payment']) &&
6a488035
TO
462 !$self->_allowWaitlist &&
463 !$realPayLater &&
464 !$self->_requireApproval &&
465 !(CRM_Utils_Array::value('amount', $self->_params[0], 0) == 0) &&
466 $totalParticipants < $self->_availableRegistrations
467 ) {
468 $errors['_qf_default'] = ts("Your event registration will be confirmed. Please go back to the main registration page, to complete payment information.");
469 }
470 //check for availability of registrations.
8cc574cf 471 if (!$self->_allowConfirmation && empty($self->_values['event']['has_waitlist']) &&
6a488035
TO
472 $totalParticipants > $self->_availableRegistrations
473 ) {
be2fb01f 474 $errors['_qf_default'] = ts('Sorry, it looks like this event only has %2 spaces available, and you are trying to register %1 participants. Please change your selections accordingly.', [
90b461f1
SL
475 1 => $totalParticipants,
476 2 => $self->_availableRegistrations,
477 ]);
6a488035
TO
478 }
479 }
480 }
481 }
482
8cc574cf 483 if ($button == 'skip' && $self->_lastParticipant && !empty($fields['priceSetId'])) {
9da8dc8c 484 $pricesetFieldsCount = CRM_Price_BAO_PriceSet::getPricesetCount($fields['priceSetId']);
6a488035
TO
485 if (($pricesetFieldsCount < 1) || $self->_allowConfirmation) {
486 return $errors;
487 }
488
8cc574cf 489 if (!empty($self->_values['event']['has_waitlist']) && !empty($self->_params[0]['bypass_payment']) &&
6a488035
TO
490 !$self->_allowWaitlist &&
491 !$realPayLater &&
492 !$self->_requireApproval &&
493 !(CRM_Utils_Array::value('amount', $self->_params[0], 0) == 0)
494 ) {
495 $errors['_qf_default'] = ts("You are going to skip the last participant, your event registration will be confirmed. Please go back to the main registration page, to complete payment information.");
496 }
497 }
498
6a488035
TO
499 if ($button != 'skip' &&
500 $self->_values['event']['is_monetary'] &&
501 !isset($errors['_qf_default']) &&
502 !$self->validatePaymentValues($self, $fields)
503 ) {
504 $errors['_qf_default'] = ts("Your payment information looks incomplete. Please go back to the main registration page, to complete payment information.");
505 $self->set('forcePayement', TRUE);
506 }
507 elseif ($button == 'skip') {
508 $self->set('forcePayement', TRUE);
509 }
510
511 return $errors;
512 }
513
0cf587a7 514 /**
e8cf95b4 515 * @param self $self
0cf587a7
EM
516 * @param $fields
517 *
518 * @return bool
519 */
00be9182 520 public function validatePaymentValues($self, $fields) {
6a488035 521
a7488080 522 if (!empty($self->_params[0]['bypass_payment']) ||
6a488035
TO
523 $self->_allowWaitlist ||
524 empty($self->_fields) ||
525 CRM_Utils_Array::value('amount', $self->_params[0]) > 0
526 ) {
527 return TRUE;
528 }
529
530 $validatePayement = FALSE;
a7488080 531 if (!empty($fields['priceSetId'])) {
be2fb01f 532 $lineItem = [];
9da8dc8c 533 CRM_Price_BAO_PriceSet::processAmount($self->_values['fee'], $fields, $lineItem);
6a488035
TO
534 if ($fields['amount'] > 0) {
535 $validatePayement = TRUE;
6a488035
TO
536 // return false;
537 }
538 }
a7488080 539 elseif (!empty($fields['amount']) &&
6a488035
TO
540 (CRM_Utils_Array::value('value', $self->_values['fee'][$fields['amount']]) > 0)
541 ) {
542 $validatePayement = TRUE;
543 }
544
545 if (!$validatePayement) {
6a488035 546 return TRUE;
6a488035
TO
547 }
548
be2fb01f 549 $errors = [];
7cb3d4f0
CW
550
551 CRM_Core_Form::validateMandatoryFields($self->_fields, $fields, $errors);
6a488035 552
5ec4b965 553 if (isset($self->_params[0]['payment_processor'])) {
554 // validate supplied payment instrument values (e.g. credit card number and cvv)
555 $payment_processor_id = $self->_params[0]['payment_processor'];
556 CRM_Core_Payment_Form::validatePaymentInstrument($payment_processor_id, $self->_params[0], $errors, (!$self->_isBillingAddressRequiredForPayLater ? NULL : 'billing'));
557 }
0dc0b759 558 if (!empty($errors)) {
7cb3d4f0 559 return FALSE;
6a488035 560 }
7cb3d4f0 561
6a488035
TO
562 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
563 if ($greetingType = CRM_Utils_Array::value($greeting, $self->_params[0])) {
233319bf 564 $customizedValue = CRM_Core_PseudoConstant::getKey('CRM_Contact_BAO_Contact', $greeting . '_id', 'Customized');
6a488035
TO
565 if ($customizedValue == $greetingType && empty($self->_params[0][$greeting . '_custom'])) {
566 return FALSE;
567 }
568 }
569 }
2ae4d103 570 return TRUE;
6a488035
TO
571 }
572
573 /**
66f9e52b 574 * Process the form submission.
6a488035 575 *
6a488035 576 *
355ba699 577 * @return void
6a488035
TO
578 */
579 public function postProcess() {
580 //get the button name.
581 $button = substr($this->controller->getButtonName(), -4);
582
583 //take the participant instance.
584 $addParticipantNum = substr($this->_name, 12);
585
586 //user submitted params.
587 $params = $this->controller->exportValues($this->_name);
588
589 if (!$this->_allowConfirmation) {
590 // check if the participant is already registered
7dfe13ab 591 $params['contact_id'] = CRM_Event_Form_Registration_Register::getRegistrationContactID($params, $this, TRUE);
6a488035
TO
592 }
593
f5a47ead 594 if (!empty($params['image_URL'])) {
595 CRM_Contact_BAO_Contact::processImageParams($params);
596 }
6a488035
TO
597 //carry campaign to partcipants.
598 if (array_key_exists('participant_campaign_id', $params)) {
599 $params['campaign_id'] = $params['participant_campaign_id'];
600 }
601 else {
9c1bc317 602 $params['campaign_id'] = $this->_values['event']['campaign_id'] ?? NULL;
6a488035
TO
603 }
604
605 // if waiting is enabled
606 if (!$this->_allowConfirmation &&
607 is_numeric($this->_availableRegistrations)
608 ) {
609 $this->_allowWaitlist = FALSE;
610 //get the current page count.
611 $currentCount = self::getParticipantCount($this, $params);
612 if ($button == 'skip') {
613 $currentCount = 'skip';
614 }
615
616 //get the total count.
617 $previousCount = self::getParticipantCount($this, $this->_params, TRUE);
618 $totalParticipants = $previousCount;
619 if (is_numeric($currentCount)) {
620 $totalParticipants += $currentCount;
621 }
a7488080 622 if (!empty($this->_values['event']['has_waitlist']) &&
6a488035
TO
623 $totalParticipants > $this->_availableRegistrations
624 ) {
625 $this->_allowWaitlist = TRUE;
626 }
627 $this->set('allowWaitlist', $this->_allowWaitlist);
628 $this->_lineItemParticipantsCount[$addParticipantNum] = $currentCount;
629 }
630
631 if ($button == 'skip') {
632 //hack for free/zero amount event.
633 if ($this->_resetAllowWaitlist) {
634 $this->_allowWaitlist = FALSE;
635 $this->set('allowWaitlist', FALSE);
636 if ($this->_requireApproval) {
637 $status = ts("You have skipped last participant and which result into event having enough spaces, but your registration require 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.");
638 }
639 else {
640 $status = ts("You have skipped last participant and which result into event having enough spaces, hence your group become as register participants though you selected on wait list.");
641 }
642 CRM_Core_Session::setStatus($status);
643 }
644
645 $this->_params[$addParticipantNum] = 'skip';
646 if (isset($this->_lineItem)) {
647 $this->_lineItem[$addParticipantNum] = 'skip';
648 $this->_lineItemParticipantsCount[$addParticipantNum] = 'skip';
649 }
650 }
651 else {
652
653 $config = CRM_Core_Config::singleton();
654 $params['currencyID'] = $config->defaultCurrency;
655
656 if ($this->_values['event']['is_monetary']) {
657
658 //added for discount
659 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
c039f658 660 $params['amount_level'] = $this->getAmountLevel($params, $discountId);
6a488035
TO
661 if (!empty($this->_values['discount'][$discountId])) {
662 $params['discount_id'] = $discountId;
6a488035
TO
663 $params['amount'] = $this->_values['discount'][$discountId][$params['amount']]['value'];
664 }
665 elseif (empty($params['priceSetId'])) {
6a488035
TO
666 $params['amount'] = $this->_values['fee'][$params['amount']]['value'];
667 }
668 else {
be2fb01f 669 $lineItem = [];
9da8dc8c 670 CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem);
6a488035 671
0dc0b759 672 //build line item array..
673 //if requireApproval/waitlist is enabled we hide fees for primary participant
674 // (and not for additional participant which might be is a bug)
675 //lineItem are not correctly build for primary participant
676 //this results in redundancy since now lineItems for additional participant will be build against primary participantNum
677 //therefore lineItems must always be build against current participant No
678 $this->_lineItem[$addParticipantNum] = $lineItem;
6a488035
TO
679 }
680 }
681
682 if (array_key_exists('participant_role', $params)) {
683 $params['participant_role_id'] = $params['participant_role'];
684 }
685
a7488080 686 if (empty($params['participant_role_id']) && $this->_values['event']['default_role_id']) {
6a488035
TO
687 $params['participant_role_id'] = $this->_values['event']['default_role_id'];
688 }
689
a7488080 690 if (!empty($this->_params[0]['is_pay_later'])) {
6a488035
TO
691 $params['is_pay_later'] = 1;
692 }
693
694 //carry additional participant id, contact id if pre-registered.
695 if ($this->_allowConfirmation && $this->_additionalParticipantId) {
696 $params['contact_id'] = $this->_contactId;
697 $params['participant_id'] = $this->_additionalParticipantId;
698 }
699
700 //build the params array.
0dc0b759 701 $this->_params[$addParticipantNum] = $params;
6a488035
TO
702 }
703
704 //finally set the params.
705 $this->set('params', $this->_params);
706 //set the line item.
707 if ($this->_lineItem) {
708 $this->set('lineItem', $this->_lineItem);
709 $this->set('lineItemParticipantsCount', $this->_lineItemParticipantsCount);
710 }
711
712 $participantNo = count($this->_params);
713 if ($button != 'skip') {
be2fb01f 714 $statusMsg = ts('Registration information for participant %1 has been saved.', [1 => $participantNo]);
6a488035
TO
715 CRM_Core_Session::setStatus($statusMsg, ts('Registration Saved'), 'success');
716 }
717
1909126f 718 // Check whether to process the registration now, calling processRegistration()
719 if (
90b461f1
SL
720 // CRM-11182 - Optional confirmation screen
721 !$this->_values['event']['is_confirm_enabled']
d6121d3e 722 && !$this->_values['event']['is_monetary']
b99f3e96 723 && !empty($this->_params[0]['additional_participants'])
1909126f 724 && $this->isLastParticipant()
6a488035 725 ) {
3033e657 726 $this->processRegistration($this->_params);
6a488035
TO
727 }
728 }
729
0cf587a7
EM
730 /**
731 * @param $additionalParticipant
732 *
733 * @return array
734 */
5dd94759 735 public static function &getPages($additionalParticipant) {
be2fb01f 736 $details = [];
6a488035 737 for ($i = 1; $i <= $additionalParticipant; $i++) {
be2fb01f 738 $details["Participant_{$i}"] = [
6a488035
TO
739 'className' => 'CRM_Event_Form_Registration_AdditionalParticipant',
740 'title' => "Register Additional Participant {$i}",
be2fb01f 741 ];
6a488035
TO
742 }
743 return $details;
744 }
745
746 /**
66f9e52b 747 * Check whether call current participant is last one.
6a488035 748 *
2a6da8d7
EM
749 * @param bool $isButtonJs
750 *
608e6658 751 * @return bool
a6c01b45 752 * ture on success.
6a488035 753 */
00be9182 754 public function isLastParticipant($isButtonJs = FALSE) {
6a488035
TO
755 $participant = $isButtonJs ? $this->_params[0]['additional_participants'] : $this->_params[0]['additional_participants'] + 1;
756 if (count($this->_params) == $participant) {
757 return TRUE;
758 }
759 return FALSE;
760 }
a14eff52 761
6a488035 762}