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